feat(otel): record uncaught expections (#1191)

pull/1192/head
Jocelyn Boullier 2025-06-08 04:31:28 +02:00 committed by GitHub
parent d05b6158ec
commit a70d91950f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 21 additions and 0 deletions

View File

@ -0,0 +1,5 @@
---
'@hono/otel': patch
---
Record uncaught exceptions as events attached to the request span

View File

@ -7,6 +7,9 @@ import {
ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_RESPONSE_STATUS_CODE,
ATTR_URL_FULL, ATTR_URL_FULL,
ATTR_HTTP_ROUTE, ATTR_HTTP_ROUTE,
ATTR_EXCEPTION_MESSAGE,
ATTR_EXCEPTION_TYPE,
ATTR_EXCEPTION_STACKTRACE,
} from '@opentelemetry/semantic-conventions' } from '@opentelemetry/semantic-conventions'
import { Hono } from 'hono' import { Hono } from 'hono'
import { otel } from '.' import { otel } from '.'
@ -65,6 +68,15 @@ describe('OpenTelemetry middleware', () => {
expect(span.attributes[ATTR_HTTP_REQUEST_METHOD]).toBe('POST') expect(span.attributes[ATTR_HTTP_REQUEST_METHOD]).toBe('POST')
expect(span.attributes[ATTR_URL_FULL]).toBe('http://localhost/error') expect(span.attributes[ATTR_URL_FULL]).toBe('http://localhost/error')
expect(span.attributes[ATTR_HTTP_ROUTE]).toBe('/error') expect(span.attributes[ATTR_HTTP_ROUTE]).toBe('/error')
expect(span.events.length).toBe(1)
const [event] = span.events
expect(event.attributes).toBeDefined()
const attributes = event.attributes!
expect(attributes[ATTR_EXCEPTION_TYPE]).toBe('Error')
expect(attributes[ATTR_EXCEPTION_MESSAGE]).toBe('error message')
expect(attributes[ATTR_EXCEPTION_STACKTRACE]).toEqual(
expect.stringMatching(/Error: error message\n.*at \S+\/src\/index.test.ts:\d+:\d+\n/)
)
}) })
it('Should update the active span', async () => { it('Should update the active span', async () => {

View File

@ -75,9 +75,13 @@ export const otel = <E extends Env = any, P extends string = any, I extends Inpu
span.setAttribute(ATTR_HTTP_RESPONSE_HEADER(name), value) span.setAttribute(ATTR_HTTP_RESPONSE_HEADER(name), value)
} }
if (c.error) { if (c.error) {
span.recordException(c.error)
span.setStatus({ code: SpanStatusCode.ERROR, message: String(c.error) }) span.setStatus({ code: SpanStatusCode.ERROR, message: String(c.error) })
} }
} catch (e) { } catch (e) {
if (e instanceof Error) {
span.recordException(e)
}
span.setStatus({ code: SpanStatusCode.ERROR, message: String(e) }) span.setStatus({ code: SpanStatusCode.ERROR, message: String(e) })
throw e throw e
} finally { } finally {