-
Notifications
You must be signed in to change notification settings - Fork 124
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
WIP: OpenTelemetry logger #1043
base: master
Are you sure you want to change the base?
Conversation
if (requestOptions?.log?.injectHeaders) { | ||
requestOptions.log.injectHeaders(fetchHeaders); |
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.
This is a bit hacky, but it is where propagation headers are injected. What header exactly is being injected is defined by the propagator when initialising the OTEL SDK.
This also probably breaks if the server doesn't allow the uber-trace-id
header in the CORS
const resource = new Resource({ | ||
[SemanticResourceAttributes.SERVICE_NAME]: 'hydrogen-web', | ||
}); | ||
const detectedResources = await detectResources({ detectors: [browserDetector] }); | ||
|
||
const provider = new WebTracerProvider({ | ||
resource: resource.merge(detectedResources), | ||
}); | ||
provider.addSpanProcessor(new BatchSpanProcessor(new OTLPTraceExporter())); | ||
provider.register({ propagator: new JaegerPropagator() }); |
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.
This does a bunch of things.
The 'resources' are K/V that are attached to all the spans. The browserDetector
will automatically add the browser name and version in those resourceS.
Then the WebTracerProvider
provides the OTEL API implementation, and it registers itself as the global provider. We could also pass that to the OTEL logger instead if don't want to pollute some global variable.
function itemCaption(values: LogItemValues): string { | ||
if (values.t === "network") { | ||
return `HTTP request`; | ||
} else { | ||
return values.l || values.t || "Log item"; | ||
} | ||
} | ||
|
||
function mapLabelToAttribute(t: string | undefined, key: string): string | null { | ||
if (key === "l") return null; | ||
if (key === "t") return null; | ||
|
||
if (t === "network") { | ||
if (key === "method") return SemanticAttributes.HTTP_METHOD; | ||
if (key === "url") return SemanticAttributes.HTTP_URL; | ||
if (key === "status") return SemanticAttributes.HTTP_STATUS_CODE; | ||
} | ||
|
||
return `hydrogen.${key}`; | ||
} | ||
|
||
function labelsToAttributes(labels: object): Attributes { | ||
return Object.entries(labels) | ||
.reduce((attrs, [key, value]) => { | ||
const mapped = mapLabelToAttribute(labels['t'], key); | ||
if (!mapped) return attrs; | ||
return { ...attrs, [mapped]: value as AttributeValue }; | ||
}, { | ||
}); | ||
} |
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.
Those functions are an attempt to map the various keys in the log entries to well-known OTEL attributes. The list of those attributes can be found here: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/README.md
This is very much WIP, but works.
It basically implements a
ILogger
which sends spans through the OpenTelemetry API.The OTEL API is a no-op by default, but here we're setting up the SDK to export to an OTLP over HTTP endpoint (localhost:4317 by default).
I've added a docker-compose stack to start the OTEL collector and a Jaeger instance to collect the traces.
It also touches a bit the HTTP client so that the trace context is injected in the HTTP headers. I have a modified Synapse somewhere to accept those headers and propagate the trace context.