-
Notifications
You must be signed in to change notification settings - Fork 22
feat(opentelemetry): create otel instrumentation for typed-express-router #1044
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
Draft
starfy84
wants to merge
5
commits into
beta
Choose a base branch
from
DX-1473-create-otel-wrapper-for-typed-express-router
base: beta
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,135
−294
Draft
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
0158ca3
feat(opentelemetry): create otel instrumentation for
ericcrosson-bitgo c044072
fix: widen the supported version for @opentelemetry/api
starfy84 a0275b1
fix: update package-lock
starfy84 c1af7da
wip: checkpoint
ericcrosson-bitgo ab8a123
chore: cleanup, pass responseFn in decode error function
starfy84 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,14 +2,19 @@ import express from 'express'; | |
import { Errors } from 'io-ts'; | ||
import * as PathReporter from 'io-ts/lib/PathReporter'; | ||
|
||
import { OnDecodeErrorFn } from './types'; | ||
|
||
export function defaultOnDecodeError( | ||
errs: Errors, | ||
_req: express.Request, | ||
res: express.Response, | ||
) { | ||
): ReturnType<OnDecodeErrorFn> { | ||
Comment on lines
7
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can simplify this thing we wrote several hours into our pair programming session last week with: export const defaultOnDecodeError: OnDecodeErrorFn = (
errs,
_req, // Use _req to indicate it's not used if you prefer
res
) => {
// ...
}; |
||
const validationErrors = PathReporter.failure(errs); | ||
const validationErrorMessage = validationErrors.join('\n'); | ||
res.status(400).json({ error: validationErrorMessage }).end(); | ||
const responseFn = () => { | ||
res.status(400).json({ error: validationErrorMessage }).end(); | ||
}; | ||
return { response: validationErrorMessage, statusCode: 400, responseFn }; | ||
} | ||
|
||
export function defaultOnEncodeError( | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* | ||
* @api-ts/typed-express-router | ||
*/ | ||
|
||
// This module handles the optional dependency on @opentelemetry/api | ||
// It provides functionality for creating spans for decode and sendEncoded operations | ||
|
||
import type { Attributes, Span, Tracer } from '@opentelemetry/api'; | ||
starfy84 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
import type { Json, SpanMetadata } from './types'; | ||
|
||
let otelApi: any; | ||
starfy84 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let tracer: Tracer | undefined; | ||
|
||
// Load @opentelemetry/api, if available. | ||
try { | ||
otelApi = require('@opentelemetry/api'); | ||
if (otelApi) { | ||
tracer = otelApi.trace.getTracer('typed-express-router'); | ||
} | ||
} catch (e) { | ||
// Optional dependency not available, so tracing will be disabled. | ||
tracer = undefined; | ||
} | ||
|
||
export const ApiTsAttributes = { | ||
/** | ||
* The Operation ID of the HTTP request | ||
*/ | ||
API_TS_OPERATION_ID: 'api_ts.operation_id', | ||
|
||
/** | ||
* The method of the HTTP request | ||
*/ | ||
API_TS_METHOD: 'api_ts.method', | ||
|
||
/** | ||
* The path of the HTTP request | ||
*/ | ||
API_TS_PATH: 'api_ts.path', | ||
|
||
/** | ||
* Returned HTTP request status code | ||
*/ | ||
API_TS_STATUS_CODE: 'api_ts.status_code', | ||
}; | ||
|
||
/** | ||
* Create default attributes for decode spans | ||
* | ||
* @param metadata The metadata for a span | ||
* @returns Record of span attributes | ||
*/ | ||
export function createDefaultDecodeAttributes(metadata: SpanMetadata): Attributes { | ||
const attributes: Attributes = {}; | ||
|
||
if (metadata.apiName) { | ||
attributes[ApiTsAttributes.API_TS_OPERATION_ID] = metadata.apiName; | ||
} | ||
|
||
if (metadata.httpRoute) { | ||
if (metadata.httpRoute.method) { | ||
attributes[ApiTsAttributes.API_TS_METHOD] = metadata.httpRoute.method; | ||
} | ||
if (metadata.httpRoute.path) { | ||
attributes[ApiTsAttributes.API_TS_PATH] = metadata.httpRoute.path; | ||
} | ||
} | ||
|
||
return attributes; | ||
} | ||
|
||
/** | ||
* Create default attributes for encode spans | ||
* | ||
* @param metadata The metadata for a span | ||
* @returns Record of span attributes | ||
*/ | ||
export function createDefaultEncodeAttributes(metadata: SpanMetadata): Attributes { | ||
const attributes: Attributes = {}; | ||
|
||
if (metadata.apiName) { | ||
attributes[ApiTsAttributes.API_TS_OPERATION_ID] = metadata.apiName; | ||
} | ||
|
||
if (metadata.httpRoute) { | ||
if (metadata.httpRoute.method) { | ||
attributes[ApiTsAttributes.API_TS_METHOD] = metadata.httpRoute.method; | ||
} | ||
if (metadata.httpRoute.path) { | ||
attributes[ApiTsAttributes.API_TS_PATH] = metadata.httpRoute.path; | ||
} | ||
} | ||
|
||
return attributes; | ||
} | ||
|
||
/** | ||
* Creates a span for the decode operation if OpenTelemetry is available | ||
* @param metadata The metadata for a span | ||
* @returns A span object or undefined if tracing is disabled | ||
*/ | ||
export function createDecodeSpan(metadata: SpanMetadata): Span | undefined { | ||
if (!tracer || !otelApi) { | ||
return undefined; | ||
} | ||
|
||
const span = tracer.startSpan(`typed-express-router.decode`); | ||
const decodeAttributes = createDefaultDecodeAttributes(metadata); | ||
span.setAttributes(decodeAttributes); | ||
|
||
return span; | ||
} | ||
|
||
/** | ||
* Creates a span for the sendEncoded operation if OpenTelemetry is available | ||
* @param metadata The metadata for a span | ||
* @returns A span object or undefined if tracing is disabled | ||
*/ | ||
export function createSendEncodedSpan(metadata: SpanMetadata): Span | undefined { | ||
if (!tracer || !otelApi) { | ||
return undefined; | ||
} | ||
|
||
const span = tracer.startSpan(`typed-express-router.encode`); | ||
|
||
const encodeAttributes = createDefaultEncodeAttributes(metadata); | ||
// Add attributes to provide context for the span | ||
span.setAttributes(encodeAttributes); | ||
|
||
return span; | ||
} | ||
|
||
/** | ||
* Records an error on an encode span | ||
* @param span The span to record the error on | ||
* @param error The error to record | ||
*/ | ||
export function recordSpanEncodeError(span: Span | undefined, error: unknown): void { | ||
if (!span || !otelApi) { | ||
return; | ||
} | ||
span.recordException(error instanceof Error ? error : new Error(String(error))); | ||
span.setStatus({ code: otelApi.SpanStatusCode.ERROR }); | ||
} | ||
|
||
/** | ||
* Records errors on a decode span | ||
* @param span The span to record the errors on | ||
* @param error The JSON error value to record | ||
* @param statusCode The HTTP status code | ||
*/ | ||
export function recordSpanDecodeError( | ||
span: Span | undefined, | ||
error: Json, | ||
statusCode: number, | ||
): void { | ||
if (!span || !otelApi) { | ||
return; | ||
} | ||
setSpanAttributes(span, { | ||
[ApiTsAttributes.API_TS_STATUS_CODE]: statusCode, | ||
}); | ||
span.recordException(JSON.stringify(error, null, 2)); | ||
span.setStatus({ code: otelApi.SpanStatusCode.ERROR }); | ||
} | ||
|
||
/** | ||
* Sets a span's attributes if it exists | ||
* @param span The span to modify | ||
* @param attributes The attributes to modify the span with | ||
*/ | ||
export function setSpanAttributes( | ||
span: Span | undefined, | ||
attributes: Attributes, | ||
): void { | ||
if (!span) { | ||
return; | ||
} | ||
span.setAttributes(attributes); | ||
} | ||
|
||
/** | ||
* Ends a span if it exists | ||
* @param span The span to end | ||
*/ | ||
export function endSpan(span: Span | undefined): void { | ||
if (!span) { | ||
return; | ||
} | ||
span.end(); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
express-wrapper
modified due toonDecodeError
return type being changed