-
Notifications
You must be signed in to change notification settings - Fork 13
SigV4 Authentication Support for OTLP HTTP Logs Exporter #181
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
base: main
Are you sure you want to change the base?
Conversation
Can we support Pino as well? We mention it in our docs and is considered top 2 popular logging libraries for Node.js.
|
@@ -83,6 +84,9 @@ try { | |||
diag.info('Setting TraceProvider for instrumentations at the end of initialization'); | |||
for (const instrumentation of instrumentations) { | |||
instrumentation.setTracerProvider(trace.getTracerProvider()); | |||
if (instrumentation.setLoggerProvider) { | |||
instrumentation.setLoggerProvider(logs.getLoggerProvider()); |
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.
Wondering if this is required? Since Global Logger Provider is also set here: https://github.com/open-telemetry/opentelemetry-js/blob/v1.30.1/experimental/packages/opentelemetry-sdk-node/src/sdk.ts#L401
Does this feature without this setLoggerProvider
code?
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.
Yep confirmed this works without the setLoggerProvider
...tro-opentelemetry-node-autoinstrumentation/src/exporter/otlp/aws/common/aws-authenticator.ts
Show resolved
Hide resolved
* sending it to the endpoint. Otherwise, we will skip signing. | ||
*/ | ||
public override async export(items: ReadableSpan[], resultCallback: (result: ExportResult) => void): Promise<void> { | ||
const serializedSpans: Uint8Array | undefined = ProtobufTraceSerializer.serializeRequest(items); |
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.
Previously, we return right away and do nothing if serializedSpans
was undefined, but not anymore in the new change. Is there a reason for this, was it because it was redundant because the super call would also do nothing (I didn't check the super method logic)?
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.
added the immediate return back if serializedSpans is undefined
...pentelemetry-node-autoinstrumentation/src/exporter/otlp/aws/traces/otlp-aws-span-exporter.ts
Show resolved
Hide resolved
// Cleans up Sigv4 from headers to avoid accidentally copying them to the new headers | ||
private removeSigV4Headers(headers: Record<string, string>) { | ||
const newHeaders: Record<string, string> = {}; | ||
const sigV4Headers = ['x-amz-date', 'authorization', 'x-amz-content-sha256', 'x-amz-security-token']; |
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.
You could move this to be a constant outside of this class.
const signer = new SignatureV4({ | ||
credentials: defaultProvider(), | ||
region: this.region, | ||
service: this.service, | ||
sha256: Sha256, | ||
}); |
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 can be a class member, no need to create this object for every authentication.
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.
I believe we need to since defaultProvider()
needs to be called in every export to ensure we're passing in the latest credentials.
|
||
for (const pair of logsHeaders.split(',')) { | ||
if (pair.includes('=')) { | ||
const [key, value] = pair.split('=', 2); |
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.
fyi, this makes it so that 'a=b=c'.split('=', 2)
become ["a", "b"]
, not ["a", "b=c"]
You may want to consider this approach if this is a concern:
Lines 299 to 303 in 241fa38
for (const arg of args) { | |
const equalIndex: number = arg.indexOf('='); | |
if (equalIndex === -1) { | |
continue; | |
} |
But based on the logic, you don't care about the value, so it may not be a concern.
if (filteredLogHeadersCount !== 2) { | ||
diag.warn( | ||
'Improper configuration: Please configure the environment variable OTEL_EXPORTER_OTLP_LOGS_HEADERS ' + | ||
'to have values for x-aws-log-group and x-aws-log-stream' |
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.
'to have values for x-aws-log-group and x-aws-log-stream' | |
`to have values for ${AWS_OTLP_LOGS_GROUP_HEADER} and ${AWS_OTLP_LOGS_STREAM_HEADER}` |
} | ||
} | ||
|
||
if (filteredLogHeadersCount !== 2) { |
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.
Technically, a user can just set x-aws-log-group
twice, and that would cause validateLogsHeaders()
to be true. To get around this, you can just split the (key === AWS_OTLP_LOGS_GROUP_HEADER || key === AWS_OTLP_LOGS_STREAM_HEADER)
check into an if-elseif statement and just validate that both statements are entered.
Yep should also support Pino as well, I missed that in the description. |
Issue #, if available:
Supporting ADOT JS auto instrumentation to automatically inject SigV4 authentication headers for outgoing log requests to the allow exporting to the AWS Logs OTLP endpoint. Users will need to configure the following environment variables in order to enable and properly run this exporter:
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://logs.[AWS-REGION].amazonaws.com/v1/logs
; requiredOTEL_EXPORTER_OTLP_LOGS_HEADERS
=x-aws-log-group=[CW-LOG-GROUP-NAME],x-aws-log-stream=[CW-LOG-STREAM-NAME]
requiredOTEL_LOGS_EXPORTER=otlp
required or do not set env variableOTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf
required or do not set env variableOTEL_METRICS_EXPORTER=none
This feature currently supports only 2 logging libraries by auto-instrumentation,
Bunyan
andWinston
:https://docs.honeycomb.io/send-data/logs/opentelemetry/sdk/javascript/
Description of changes:
Add new AwsAuthenticator class used by both OtlpAwsLogExporter and OtlpAwsSpanExporter which extends the upstream OTLPProtoLogExporter to inject Sigv4 headers directly into the headers.
Modified ADOT JS auto instrumentation to automatically detect if a user is exporting to CW Logs OTLP Logs endpoint by checking if the environment variable
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
is configured to match this url pattern:https://logs.[AWS-REGION].amazonaws.com/v1/logs
Testing:
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Example log in CW Logs: