Skip to content
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

[APM][OTel] Use telemetry.sdk as a fallback for missing agent.name on non-tracing data #196529

Merged
4 changes: 4 additions & 0 deletions packages/kbn-apm-types/src/es_fields/apm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ export const METRIC_OTEL_JVM_SYSTEM_CPU_PERCENT = 'process.runtime.jvm.system.cp
export const METRIC_OTEL_JVM_GC_DURATION = 'process.runtime.jvm.gc.duration';
export const VALUE_OTEL_JVM_PROCESS_MEMORY_HEAP = 'heap';
export const VALUE_OTEL_JVM_PROCESS_MEMORY_NON_HEAP = 'non_heap';
// OpenTelemetry semconv fields for AgentName https://opentelemetry.io/docs/specs/semconv/resource/#telemetry-sdk
export const TELEMETRY_SDK_NAME = 'telemetry.sdk.name';
rmyz marked this conversation as resolved.
Show resolved Hide resolved
export const TELEMETRY_SDK_LANGUAGE = 'telemetry.sdk.language';
export const TELEMETRY_SDK_VERSION = 'telemetry.sdk.version';

// Metadata
export const TIER = '_tier';
Expand Down
8 changes: 8 additions & 0 deletions packages/kbn-elastic-agent-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ A utility package providing functions for working with Elastic Agents. This pack

## Functions

- **`getAgentName`**

```typescript
export function getAgentName(agentName: string | null, telemetryAgentName: string | null, telemetrySdkName: string | null): AgentName;
```

Tries to get the correct agent name, `agentName` is the first option, if it fails checks if `telemetryAgentName` and `telemetrySdkName` are defined and return them as `telemetrySdkName/telemetryAgentName`, if not, `telemetryAgentName` is returned

- **`isOpenTelemetryAgentName`**

```typescript
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-elastic-agent-utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

export {
getAgentName,
isOpenTelemetryAgentName,
hasOpenTelemetryPrefix,
isJavaAgentName,
Expand Down
13 changes: 13 additions & 0 deletions packages/kbn-elastic-agent-utils/src/agent_guards.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import {
getAgentName,
hasOpenTelemetryPrefix,
isAndroidAgentName,
isAWSLambdaAgentName,
Expand Down Expand Up @@ -119,4 +120,16 @@ describe('Agents guards', () => {
expect(isAzureFunctionsAgentName('azure.functions')).toBe(true);
expect(isAzureFunctionsAgentName('not-an-agent')).toBe(false);
});

it('getAgentName returns agent name by default', () => {
expect(getAgentName('nodejs', 'go', 'otlp')).toBe('nodejs');
});

it('getAgentName returns telemetry sdk name and telemetry agent name if agent name is not defined', () => {
expect(getAgentName(null, 'go', 'otlp')).toBe('otlp/go');
});

it('getAgentName returns telemetry agent name if agent name and telemetry sdk are not defined', () => {
expect(getAgentName(null, 'go', null)).toBe('go');
});
});
16 changes: 16 additions & 0 deletions packages/kbn-elastic-agent-utils/src/agent_guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@ import type {
ServerlessType,
} from './agent_names';

export function getAgentName(
agentName: string | null,
telemetryAgentName: string | null,
telemetrySdkName: string | null
) {
if (agentName) {
return agentName;
}

if (telemetrySdkName && telemetryAgentName) {
return `${telemetrySdkName}/${telemetryAgentName}`;
}

return telemetryAgentName;
}

export function hasOpenTelemetryPrefix(agentName?: string, language: string = '') {
if (!agentName) {
return false;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { rangeQuery } from '@kbn/observability-plugin/server';
import { ProcessorEvent } from '@kbn/observability-plugin/common';
import { unflattenKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
import { FlattenedApmEvent } from '@kbn/apm-data-access-plugin/server/utils/unflatten_known_fields';
import { getAgentName } from '@kbn/elastic-agent-utils';
import { environmentQuery } from '../../../common/utils/environment_query';
import {
CLOUD_AVAILABILITY_ZONE,
Expand All @@ -21,6 +22,11 @@ import {
SERVICE_VERSION,
FAAS_ID,
FAAS_TRIGGER_TYPE,
AGENT_NAME,
TELEMETRY_SDK_LANGUAGE,
TELEMETRY_SDK_NAME,
AGENT_VERSION,
TELEMETRY_SDK_VERSION,
} from '../../../common/es_fields/apm';
import { ContainerType } from '../../../common/service_metadata';
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
Expand Down Expand Up @@ -158,7 +164,25 @@ export async function getServiceMetadataDetails({
},
};

const response = await apmEventClient.search('get_service_metadata_details', params);
const data = await apmEventClient.search('get_service_metadata_details', params);

if (data.hits.total.value === 0) {
return {
service: undefined,
container: undefined,
cloud: undefined,
};
}

const response = structuredClone(data);
response.hits.hits[0].fields[AGENT_NAME] = getAgentName(
data.hits.hits[0]?.fields?.[AGENT_NAME] as unknown as string | null,
data.hits.hits[0]?.fields?.[TELEMETRY_SDK_LANGUAGE] as unknown as string | null,
data.hits.hits[0]?.fields?.[TELEMETRY_SDK_NAME] as unknown as string | null
) as unknown as unknown[];
response.hits.hits[0].fields[AGENT_VERSION] =
response.hits.hits[0].fields[AGENT_VERSION] ??
data.hits.hits[0]?.fields?.[TELEMETRY_SDK_VERSION];

const event = unflattenKnownApmEventFields(
maybe(response.hits.hits[0])?.fields as undefined | FlattenedApmEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { rangeQuery } from '@kbn/observability-plugin/server';
import { ProcessorEvent } from '@kbn/observability-plugin/common';
import { unflattenKnownApmEventFields } from '@kbn/apm-data-access-plugin/server/utils';
import type { FlattenedApmEvent } from '@kbn/apm-data-access-plugin/server/utils/unflatten_known_fields';
import { getAgentName } from '@kbn/elastic-agent-utils';
import { maybe } from '../../../common/utils/maybe';
import { asMutableArray } from '../../../common/utils/as_mutable_array';
import {
Expand All @@ -22,6 +23,8 @@ import {
LABEL_TELEMETRY_AUTO_VERSION,
AGENT_VERSION,
SERVICE_FRAMEWORK_NAME,
TELEMETRY_SDK_NAME,
TELEMETRY_SDK_LANGUAGE,
} from '../../../common/es_fields/apm';
import { ContainerType, SERVICE_METADATA_KUBERNETES_KEYS } from '../../../common/service_metadata';
import { getProcessorEventForTransactions } from '../../lib/helpers/transactions';
Expand Down Expand Up @@ -66,6 +69,8 @@ export async function getServiceMetadataIcons({
CONTAINER_ID,
AGENT_NAME,
CLOUD_SERVICE_NAME,
TELEMETRY_SDK_NAME,
TELEMETRY_SDK_LANGUAGE,
...SERVICE_METADATA_KUBERNETES_KEYS,
] as const);

Expand All @@ -85,9 +90,9 @@ export async function getServiceMetadataIcons({
},
};

const response = await apmEventClient.search('get_service_metadata_icons', params);
const data = await apmEventClient.search('get_service_metadata_icons', params);

if (response.hits.total.value === 0) {
if (data.hits.total.value === 0) {
return {
agentName: undefined,
containerType: undefined,
Expand All @@ -96,6 +101,13 @@ export async function getServiceMetadataIcons({
};
}

const response = structuredClone(data);
response.hits.hits[0].fields[AGENT_NAME] = getAgentName(
data.hits.hits[0]?.fields?.[AGENT_NAME] as unknown as string | null,
data.hits.hits[0]?.fields?.[TELEMETRY_SDK_LANGUAGE] as unknown as string | null,
data.hits.hits[0]?.fields?.[TELEMETRY_SDK_NAME] as unknown as string | null
) as unknown as unknown[];

const event = unflattenKnownApmEventFields(
maybe(response.hits.hits[0])?.fields as undefined | FlattenedApmEvent
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
*/

import { kqlQuery, rangeQuery, wildcardQuery } from '@kbn/observability-plugin/server';
import { getAgentName } from '@kbn/elastic-agent-utils';
import { ApmDocumentType } from '../../../../common/document_type';
import {
AGENT_NAME,
SERVICE_ENVIRONMENT,
SERVICE_NAME,
TRANSACTION_TYPE,
SERVICE_OVERFLOW_COUNT,
TELEMETRY_SDK_NAME,
TELEMETRY_SDK_LANGUAGE,
} from '../../../../common/es_fields/apm';
import { RollupInterval } from '../../../../common/rollup';
import { ServiceGroup } from '../../../../common/service_groups';
Expand Down Expand Up @@ -124,6 +127,16 @@ export async function getServiceTransactionStats({
size: maxNumServices,
},
aggs: {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

I don't know if this is the best place in the query for this.

telemetryAgentName: {
terms: {
field: TELEMETRY_SDK_LANGUAGE,
},
},
telemetrySdkName: {
terms: {
field: TELEMETRY_SDK_NAME,
},
},
transactionType: {
terms: {
field: TRANSACTION_TYPE,
Expand Down Expand Up @@ -169,9 +182,11 @@ export async function getServiceTransactionStats({
topTransactionTypeBucket?.environments.buckets.map(
(environmentBucket) => environmentBucket.key as string
) ?? [],
agentName: topTransactionTypeBucket?.sample.top[0].metrics[AGENT_NAME] as
| AgentName
| undefined,
agentName: getAgentName(
topTransactionTypeBucket?.sample.top[0].metrics[AGENT_NAME] as string | null,
bucket.telemetryAgentName.buckets[0]?.key as string | null,
bucket.telemetrySdkName.buckets[0]?.key as string | null
) as AgentName,
latency: topTransactionTypeBucket?.avg_duration.value,
transactionErrorRate: topTransactionTypeBucket
? calculateFailedTransactionRate(topTransactionTypeBucket)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@

import { kqlQuery, rangeQuery, wildcardQuery } from '@kbn/observability-plugin/server';
import { ProcessorEvent } from '@kbn/observability-plugin/common';
import { getAgentName } from '@kbn/elastic-agent-utils';
import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent';
import { AGENT_NAME, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm';
import {
AGENT_NAME,
SERVICE_ENVIRONMENT,
SERVICE_NAME,
TELEMETRY_SDK_LANGUAGE,
TELEMETRY_SDK_NAME,
} from '../../../../common/es_fields/apm';
import { environmentQuery } from '../../../../common/utils/environment_query';
import { ServiceGroup } from '../../../../common/service_groups';
import { RandomSampler } from '../../../lib/helpers/get_random_sampler';
Expand Down Expand Up @@ -99,6 +106,16 @@ export async function getServicesWithoutTransactions({
field: SERVICE_ENVIRONMENT,
},
},
telemetryAgentName: {
terms: {
field: TELEMETRY_SDK_LANGUAGE,
},
},
telemetrySdkName: {
terms: {
field: TELEMETRY_SDK_NAME,
},
},
latest: {
top_metrics: {
metrics: [{ field: AGENT_NAME } as const],
Expand All @@ -122,7 +139,11 @@ export async function getServicesWithoutTransactions({
return {
serviceName: bucket.key as string,
environments: bucket.environments.buckets.map((envBucket) => envBucket.key as string),
agentName: bucket.latest.top[0].metrics[AGENT_NAME] as AgentName,
agentName: getAgentName(
bucket.latest.top[0].metrics[AGENT_NAME] as string | null,
bucket.telemetryAgentName.buckets[0]?.key as string | null,
bucket.telemetrySdkName.buckets[0]?.key as string | null
) as AgentName,
};
}) ?? [],
maxCountExceeded,
Expand Down