Skip to content

Instantly share code, notes, and snippets.

@spencerwilson
Created May 19, 2022 00:15
Show Gist options
  • Save spencerwilson/f486b3a71d2e669c67233c1902f4eb15 to your computer and use it in GitHub Desktop.
Save spencerwilson/f486b3a71d2e669c67233c1902f4eb15 to your computer and use it in GitHub Desktop.
modifying span attributes
import { Context, SpanAttributes } from '@opentelemetry/api';
import {
ReadableSpan,
Span,
SpanProcessor,
} from '@opentelemetry/sdk-trace-base';
/**
* Intercepts `onEnd` to modify a finished Span's attributes.
* Otherwise delegates completely to a child SpanProcessor.
*/
export default class ModifyAttributesProcessor implements SpanProcessor {
// eslint-disable-next-line no-useless-constructor
constructor(
private modifyAttributes: (attributes: SpanAttributes) => SpanAttributes,
private childProcessor: SpanProcessor
) {}
/**
* Forces to export all finished spans
*/
forceFlush(): Promise<void> {
return this.childProcessor.forceFlush();
}
/**
* Called when a {@link Span} is started, if the `span.isRecording()`
* returns true.
* @param span the Span that just started.
*/
onStart(span: Span, parentContext: Context): void {
return this.childProcessor.onStart(span, parentContext);
}
/**
* Called when a {@link ReadableSpan} is ended, if the `span.isRecording()`
* returns true.
* @param span the Span that just ended.
*/
onEnd(span: ReadableSpan): void {
const newSpan = Object.assign(span, {
attributes: this.modifyAttributes(span.attributes),
});
return this.childProcessor.onEnd(newSpan);
}
/**
* Shuts down the processor. Called when SDK is shut down. This is an
* opportunity for processor to do any cleanup required.
*/
shutdown(): Promise<void> {
return this.childProcessor.shutdown();
}
}
import { SpanAttributes } from '@opentelemetry/api';
// This matches `auth=<JWS Compact Serialization>`. JWS Compact Serializations
// include unencrypted JWTs.
const AUTH_PARAM_REGEX = /auth=(?:[\w-]*\.){2}[\w-]*/g;
export default function redactAttributes(
attributes: SpanAttributes
): SpanAttributes {
return Object.fromEntries(
Object.entries(attributes).map(([key, value]) => {
let newValue = value;
// Redact JWTs from URL paths.
if (typeof value === 'string') {
newValue = value.replace(AUTH_PARAM_REGEX, 'auth=****');
}
return [key, newValue];
})
);
}
// `provider` is a `TracerProvider`
provider.addSpanProcessor(
new ModifyAttributesProcessor(
// This assumes that no sampling occurred upstream of this service.
// That's true for now, but at some point the value of this
// should be using OTel-native p-values.
(attributes) =>
redactAttributes(
Object.assign(attributes, { sampleRate: TRACE_ADJUSTED_COUNT })
),
new BatchSpanProcessor(
new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' })
)
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment