91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
import { SpanKind, SpanStatusCode } from '@opentelemetry/api'
|
|
import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
|
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'
|
|
import {
|
|
ATTR_HTTP_REQUEST_METHOD,
|
|
ATTR_HTTP_RESPONSE_HEADER,
|
|
ATTR_HTTP_RESPONSE_STATUS_CODE,
|
|
ATTR_URL_FULL,
|
|
ATTR_HTTP_ROUTE,
|
|
} from '@opentelemetry/semantic-conventions'
|
|
import { Hono } from 'hono'
|
|
import { otel } from '.'
|
|
|
|
describe('OpenTelemetry middleware', () => {
|
|
const app = new Hono()
|
|
|
|
const memoryExporter = new InMemorySpanExporter()
|
|
const spanProcessor = new SimpleSpanProcessor(memoryExporter)
|
|
const tracerProvider = new NodeTracerProvider({
|
|
spanProcessors: [spanProcessor],
|
|
})
|
|
|
|
app.use(otel({ tracerProvider }))
|
|
app.get('/foo', (c) => c.text('foo'))
|
|
app.post('/error', (_) => {
|
|
throw new Error('error message')
|
|
})
|
|
|
|
const subapp = new Hono()
|
|
subapp.get('/hello', (c) => c.text('Hello from subapp!'))
|
|
subapp.get('*', (c) => c.text('Fallthrough'))
|
|
|
|
// mount subapp
|
|
app.route('/subapp', subapp)
|
|
|
|
it('Should make a span', async () => {
|
|
memoryExporter.reset()
|
|
const response = await app.request('http://localhost/foo')
|
|
const spans = memoryExporter.getFinishedSpans()
|
|
expect(spans.length).toBe(1)
|
|
const [span] = spans
|
|
expect(span.name).toBe('GET /foo')
|
|
expect(span.kind).toBe(SpanKind.SERVER)
|
|
expect(span.status.code).toBe(SpanStatusCode.UNSET)
|
|
expect(span.status.message).toBeUndefined()
|
|
expect(span.attributes[ATTR_HTTP_REQUEST_METHOD]).toBe('GET')
|
|
expect(span.attributes[ATTR_URL_FULL]).toBe('http://localhost/foo')
|
|
expect(span.attributes[ATTR_HTTP_ROUTE]).toBe('/foo')
|
|
expect(span.attributes[ATTR_HTTP_RESPONSE_STATUS_CODE]).toBe(200)
|
|
for (const [name, value] of response.headers.entries()) {
|
|
expect(span.attributes[ATTR_HTTP_RESPONSE_HEADER(name)]).toBe(value)
|
|
}
|
|
})
|
|
|
|
it('Should make a span with error', async () => {
|
|
memoryExporter.reset()
|
|
await app.request('http://localhost/error', { method: 'POST' })
|
|
const spans = memoryExporter.getFinishedSpans()
|
|
expect(spans.length).toBe(1)
|
|
const [span] = spans
|
|
expect(span.name).toBe('POST /error')
|
|
expect(span.kind).toBe(SpanKind.SERVER)
|
|
expect(span.status.code).toBe(SpanStatusCode.ERROR)
|
|
expect(span.status.message).toBe('Error: error message')
|
|
expect(span.attributes[ATTR_HTTP_REQUEST_METHOD]).toBe('POST')
|
|
expect(span.attributes[ATTR_URL_FULL]).toBe('http://localhost/error')
|
|
expect(span.attributes[ATTR_HTTP_ROUTE]).toBe('/error')
|
|
})
|
|
|
|
it('Should update the active span', async () => {
|
|
memoryExporter.reset()
|
|
await tracerProvider.getTracer('test').startActiveSpan('existing span', async () => {
|
|
await app.request('http://localhost/foo')
|
|
})
|
|
const spans = memoryExporter.getFinishedSpans()
|
|
expect(spans.length).toBe(1)
|
|
const [span] = spans
|
|
expect(span.name).toBe('GET /foo')
|
|
expect(span.attributes[ATTR_HTTP_ROUTE]).toBe('/foo')
|
|
})
|
|
|
|
// Issue #1112
|
|
it('Should set the correct span name for subapp', async () => {
|
|
memoryExporter.reset()
|
|
await app.request('http://localhost/subapp/hello')
|
|
const spans = memoryExporter.getFinishedSpans()
|
|
const [span] = spans
|
|
expect(span.name).toBe('GET /subapp/hello')
|
|
})
|
|
})
|