Skip to content

Commit

Permalink
Avoid issues with cyclic jsons when instrumentig S3 by replicating py…
Browse files Browse the repository at this point in the history
…thon's logic (#38)

* Introduce cx-wrapper wrapping handler function without using require/import hooks

* back to main branch

* fix otel-handler

* Avoid issues with cyclic jsons when instrumentig S3 by replicating python's logic
  • Loading branch information
RafalSumislawski authored Jul 4, 2024
1 parent f2838bd commit 9c5a661
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 14 deletions.
43 changes: 33 additions & 10 deletions nodejs/packages/cx-wrapper/instrumentation-init.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { diag, Span } from '@opentelemetry/api';
import { Instrumentation, registerInstrumentations } from '@opentelemetry/instrumentation';
import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk';
import { AwsInstrumentation, NormalizedResponse } from '@opentelemetry/instrumentation-aws-sdk';
import { PgResponseHookInformation } from '@opentelemetry/instrumentation-pg';
import { OTEL_PAYLOAD_SIZE_LIMIT, OtelAttributes } from './common';

Expand All @@ -15,6 +15,8 @@ export function initializeInstrumentations(): any[] {
new AwsInstrumentation({
suppressInternalInstrumentation: true,
preRequestHook: (span: Span, { request }) => {
diag.debug(`preRequestHook for ${request.serviceName}.${request.commandName}`)

const data = JSON.stringify(request.commandInput);
if (data !== undefined) {
span.setAttribute(
Expand All @@ -24,15 +26,21 @@ export function initializeInstrumentations(): any[] {
}
},
responseHook: (span, { response }) => {
const data =
'data' in response && typeof response.data === 'object'
? JSON.stringify(response.data)
: response?.data?.toString();
if (data !== undefined) {
span.setAttribute(
OtelAttributes.RPC_RESPONSE_PAYLOAD,
data.substring(0, OTEL_PAYLOAD_SIZE_LIMIT)
);
diag.debug(`responseHook for ${response.request.serviceName}.${response.request.commandName}`)
if (response.request.serviceName === 'S3') {
if ('buckets' in response && Array.isArray(response.buckets)) {
setResponsePayloadAttribute(span, JSON.stringify(response.buckets.map(b => b.Name)))
} else if ('contents' in response && Array.isArray(response.contents)) {
setResponsePayloadAttribute(span, JSON.stringify(response.contents.map(b => b.Key)))
} else if ('data' in response && typeof response.data === 'object') {
// data is too large and it contains cycles
} else {
const payload = responseDataToString(response)
setResponsePayloadAttribute(span, payload)
}
} else {
const payload = responseDataToString(response)
setResponsePayloadAttribute(span, payload)
}
},
}),
Expand All @@ -47,6 +55,21 @@ export function initializeInstrumentations(): any[] {
return instrumentations;
}

function responseDataToString(response: NormalizedResponse): string {
return 'data' in response && typeof response.data === 'object'
? JSON.stringify(response.data)
: response?.data?.toString();
}

function setResponsePayloadAttribute(span: Span, payload: string | undefined) {
if (payload !== undefined) {
span.setAttribute(
OtelAttributes.RPC_RESPONSE_PAYLOAD,
payload.substring(0, OTEL_PAYLOAD_SIZE_LIMIT)
);
}
}

function defaultConfigureInstrumentations() {
// Use require statements for instrumentation to avoid having to have transitive dependencies on all the typescript
// definitions.
Expand Down
4 changes: 2 additions & 2 deletions nodejs/packages/cx-wrapper/package-lock.json

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

4 changes: 2 additions & 2 deletions nodejs/packages/layer/package-lock.json

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

0 comments on commit 9c5a661

Please sign in to comment.