Skip to content

Commit

Permalink
feat: Add additional fields collected by the TraceKit package for sta…
Browse files Browse the repository at this point in the history
…ck traces (#383)

<!--
Thank you for contributing to the project! 💜
Please see our [OSS process
document](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md#)
to get an idea of how we operate.
-->

## Short description of the changes

Introduces the [TraceKit](https://github.com/csnover/TraceKit) package
to the web distro. Adds additional fields with the help of the
`TraceKit` package. These additional fields are prefixed with
`exception.structured_stacktrace`. Additional fields will be sent by
`GlobalErrorsInstrumentation`.

## How to verify that this has the expected result
I tested locally using the `hello-world-web` example provided by the
web-distro. Made the example to throw a simple error. This was the
result I received on Honeycomb:

<img width="848" alt="Screenshot 2024-11-07 at 3 34 27 PM"
src="https://github.com/user-attachments/assets/ac6cc8ac-2cf6-47e5-b4fa-4d21d466c160">

Big thanks to @pkanal for helping with this change!
  • Loading branch information
jairo-mendoza authored Nov 13, 2024
1 parent 8c1213c commit 43ac2d7
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/honeycomb-opentelemetry-web/package-lock.json

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

1 change: 1 addition & 0 deletions packages/honeycomb-opentelemetry-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"@opentelemetry/sdk-trace-web": "~1.27.0",
"@opentelemetry/semantic-conventions": "~1.27.0",
"shimmer": "^1.2.1",
"tracekit": "^0.4.7",
"ua-parser-js": "^1.0.37",
"web-vitals": "^4.2.3"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
SEMATTRS_EXCEPTION_STACKTRACE,
SEMATTRS_EXCEPTION_TYPE,
} from '@opentelemetry/semantic-conventions';
import { computeStackTrace, StackFrame } from 'tracekit';

export interface GlobalErrorsInstrumentationConfig
extends InstrumentationConfig {}
Expand All @@ -26,6 +27,34 @@ export class GlobalErrorsInstrumentation extends InstrumentationAbstract {
this._isEnabled = enabled;
}

_computeStackTrace = (error: Error | undefined) => {
if (!error) {
return {};
}

// OTLP does not accept arrays of objects
// breaking down the stack into arrays of strings/numbers
const structuredStack: StackFrame[] = computeStackTrace(error).stack;
const lines: number[] = [];
const columns: number[] = [];
const functions: string[] = [];
const urls: string[] = [];

for (const stackFrame of structuredStack) {
lines.push(stackFrame.line);
columns.push(stackFrame.column);
functions.push(stackFrame.func);
urls.push(stackFrame.url);
}

return {
'exception.structured_stacktrace.columns': columns,
'exception.structured_stacktrace.lines': lines,
'exception.structured_stacktrace.functions': functions,
'exception.structured_stacktrace.urls': urls,
};
};

onError = (event: ErrorEvent | PromiseRejectionEvent) => {
const error: Error | undefined =
'reason' in event ? event.reason : event.error;
Expand All @@ -35,6 +64,7 @@ export class GlobalErrorsInstrumentation extends InstrumentationAbstract {
[SEMATTRS_EXCEPTION_TYPE]: type,
[SEMATTRS_EXCEPTION_MESSAGE]: message,
[SEMATTRS_EXCEPTION_STACKTRACE]: error?.stack,
...this._computeStackTrace(error),
};
// otel spec requires at minimum these two
if (!message || !type) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ describe('Global Errors Instrumentation Tests', () => {

const span = exporter.getFinishedSpans()[0];
expect(span.name).toBe('exception');
// TODO: Mock a stack trace and test that it returns the correct keys and values
expect(span.attributes).toMatchObject({
'exception.type': 'Error',
'exception.message': 'Something happened',
'exception.stacktrace': expect.any(String),
'exception.structured_stacktrace.columns': expect.any(Array),
'exception.structured_stacktrace.lines': expect.any(Array),
'exception.structured_stacktrace.functions': expect.any(Array),
'exception.structured_stacktrace.urls': expect.any(Array),
});
});

Expand All @@ -60,4 +65,20 @@ describe('Global Errors Instrumentation Tests', () => {
});
});
});

describe('_computeStackTrace', () => {
it('should return an empty object if error is undefined', () => {
expect(instr._computeStackTrace(undefined)).toEqual({});
});

// TODO: Mock a stack trace and test that it returns the correct keys and values
it('should return an object with structured stack trace information', () => {
expect(instr._computeStackTrace(new Error('This is an error'))).toEqual({
'exception.structured_stacktrace.columns': expect.any(Array),
'exception.structured_stacktrace.lines': expect.any(Array),
'exception.structured_stacktrace.functions': expect.any(Array),
'exception.structured_stacktrace.urls': expect.any(Array),
});
});
});
});

0 comments on commit 43ac2d7

Please sign in to comment.