-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Otel collector mappings to APM agent #6
Conversation
f70eafd
to
a85fbf0
Compare
Transaction | Span | APMError, | ||
'observer' | ||
>; | ||
const hit = serviceVersionMapping(response.hits.hits[0]?.fields); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this returns APMError, special care will need to be taken. I'm not sure that fields
is capable of returning fields from error.exception.stacktrace
. We may have to depend on _source in this situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's an example query for demonstration.
GET /_search
{
"fields": ["error.exception.message","error.exception.stacktrace.exclude_from_grouping"],
"query": {
"exists": {
"field": "error.exception.message"
}
},
"size": 1
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if that's even a problem since we Pick
only observer
property from the type when doing assertion. And, this is the only usage as far I can see: https://github.com/jennypavlova/kibana/pull/6/files/f52184082c369d7f63e03b250d0a09c212644f48#diff-8c8160096093f32c6f9dd260780403b55fe20f94f2c99de76cc9d54c872cb4e8R701
I'm not entirely sure why we assert type to Transaction | Span | APMError
. I couldn't even find a way to trigger this code on my local environment. That's why I left todo
comment to double-check it later, but I think I'm out of ideas here. Do you have any suggestion?
@@ -174,6 +174,7 @@ export async function getServiceMetadataDetails({ | |||
const response = await apmEventClient.search('get_service_metadata_details', params); | |||
|
|||
const fields = response.hits.hits[0]?.fields; | |||
// todo: missing `fields` property? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't found fields
property in get_service_metadata_details
when running with otel-apm-e2e-poc
I'm not sure whether we shouldn't use fields
property here or there isn't enough data in ES or there is some backend work needed here to get this field. What do you think @bryce-b?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I'll take a closer look. It's unclear if it's only using the aggregations and fields are not required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue looks like the fields
selected in the query were copied from the _source
values, which are root attributes.
fields: [SERVICE, AGENT, HOST, CONTAINER, KUBERNETES, CLOUD, LABEL_TELEMETRY_AUTO_VERSION],
which are the values:
"fields": [
"service",
"agent",
"host",
"container",
"kubernetes",
"cloud",
"labels.telemetry_auto_version"
],
We should either use fields: ['*']
, or specify the leaf attributes we want populated : eg: service.node.name
, service.environment
, service.framework.name
, etc. instead of just service
.
links: [ | ||
{ | ||
trace: { | ||
// todo(milosz): confirm `span.links.trace.id` format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you get those? I see only single values in span.links.span.id
and span.links.trace.id
when running synthtrace scenario (span_links.ts
). Did you make some aggregations?
However, even for single values in span.links.span.id
and span.links.trace.id
indeed the mapping is incorrect because we expect an array of { trace: { id: string }; span: { id: string }; }
so we can get multiple values. With that in mind, I'm not sure how this data will be represented in fields
property.
My understanding is that in source
fields we might get:
{
span: {
link: [
{ trace: { id: 'aaa', span: { id: 'aaa' } } },
{ trace: { id: 'bbb', span: { id: 'bbb' } } },
{ trace: { id: 'ccc', span: { id: 'ccc' } } },
],
},
}
So what format does expect in fields
in this situation? I guess this is the problem with all array of object properties, I'm not sure how this is solved 😅
}; | ||
|
||
// todo(milosz): test with otel APM POC, mapping format wasn't confirmed with `fields` | ||
export const spanMapping = (fields: Partial<Record<string, unknown[]>>): Span => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that SpanRaw
has a couple of additional fields not represented here, such as stacktrace
. Do those need to be represented here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While checking it I found that get_span
can give completely different response depending on span. When I first created mapping I based it on response from edge-lite-oblt
cluster, now I checked otel-apm-e2e-poc
and received different response format. I covered two possible responses in the updated mapping, but I wonder if there are other unknown yet responses for that one. BTW I haven't found stacktrace
in neither of two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -103,7 +103,7 @@ export async function getServiceAgent({ | |||
return {}; | |||
} | |||
|
|||
const { agent, service, cloud } = normalizeFields(response.hits.hits[0].fields) as ServiceAgent; | |||
const { agent, service, cloud } = serviceAgentName(response.hits.hits[0].fields) as ServiceAgent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In most places where I used as
we can replace if with return type in the mapper- so the serviceAgentName
return type should be ServiceAgent
so we can get rid of the casting.
|
||
export const CHILD_ID = 'child.id'; | ||
|
||
export const LOG_LEVEL = 'log.level'; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Otel-specific fields (under attributes
and resource.attributes
should not be part of the new data mapping - we use those fields only in the metadata table (we need to confirm if we show them anywhere else). We should keep the mappers close to the APM types
cc: @AlexanderWert and @felixbarny I remember we discussed that, let me know if I am missing something here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was expecting the mapping in es_fields_mappings.ts
to not produce Record<string, unknown[]>
but instead types such as TransactionRaw
@@ -58,8 +56,7 @@ export async function getLinkedParentsOfSpan({ | |||
}, | |||
}); | |||
|
|||
const fields = response.hits.hits[0]?.fields; | |||
const fieldsNorm = normalizeFields(fields) as unknown as TransactionRaw | SpanRaw | undefined; | |||
const fieldsNorm = linkedParentsOfSpanMapping(response.hits.hits[0]?.fields); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlexanderWert I remember we discussed that we don't support the span links ATM so should we find a way to "skip" them or "hide" the tab in case of otel data (Together with @miloszmarcinkowski we found another UI Error we have here because of SpanLink so I am wondering how to handle that in this case)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, let's just hide stuff related to Links in the UI and NOT change the query logic for SpanLinks for now
f3c89ca
to
20a7b79
Compare
|
||
export const CHILD_ID = 'child.id'; | ||
|
||
export const LOG_LEVEL = 'log.level'; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was expecting the mapping in es_fields_mappings.ts
to not produce Record<string, unknown[]>
but instead types such as TransactionRaw
client: { | ||
ip: normalizeValue<string>(fields[CLIENT_IP]), | ||
}, | ||
http: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not be mapping specific request and response headers. It looks like any other header would be lost here. Instead, we should just generically map fields named http.request.headers.*
/http.response.headers.*
.
labels: { | ||
some_resource_attribute: normalizeValue<string>(fields[LABEL_SOME_RESOURCE_ATTRIBUTE]), | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the comment about HTTP headers, we should not hard-code specific labels and instead map any fields matching labels.*
.
}; | ||
}; | ||
|
||
export const transactionMapping = (fields: Partial<Record<string, unknown[]>>) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this returning TransactionRaw
instead of Record<string, unknown[]>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for review @felixbarny!
Record<string, unknown[]>
is the parameter type, not return type. If the return type is missing, this means that I couldn't match it with any existing type interface, but typescript does automatically define an implicit type based on the return object format. So, we're left with correct typing at the end.
Today, I have a plan to check all mappings for a possible interface type that will match the returning type.
294ac0e
to
8666c00
Compare
…ructure-serialization-logic' into bryce-192749-refactor-the-normalize-function-into-per-data-structure-serialization-logic # Conflicts: # x-pack/plugins/observability_solution/apm/server/utils/es_fields_mappings.ts
…tion-into-per-data-structure-serialization-logic added span-link normalization and fixed errors in getTransaction
…apm-ui-replacing-_source-with-fields' into 192749-refactor-the-normalize-function-into-per-data-structure-serialization-logic # Conflicts: # x-pack/plugins/observability_solution/apm/common/correlations/types.ts # x-pack/plugins/observability_solution/apm/server/routes/errors/get_error_groups/get_error_group_main_statistics.ts # x-pack/plugins/observability_solution/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts # x-pack/plugins/observability_solution/apm/server/routes/services/get_service_metadata_details.ts
634b899
into
jennypavlova:192606-poc-otel-data-with-apm-ui-replacing-_source-with-fields
Closes elastic#192749
Summary
This is part of an effort (elastic#192606) in replacing the usage of
_source
withfields
while migrating APM to Otel data collector.In this PR, we're adding mappers which expose only fields used in APM. This assures we stay type safe and we provide only necessary fields.