diff --git a/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts b/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts index b106a4236344..f4c5334f8ab6 100644 --- a/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts @@ -276,7 +276,11 @@ it('sends a streamed span envelope with correct spans for a manually started spa }, 'network.protocol.name': { type: 'string', - value: 'HTTP/1.1', + value: 'http', + }, + 'network.protocol.version': { + type: 'string', + value: '1.1', }, }, is_segment: true, diff --git a/dev-packages/e2e-tests/test-applications/cloudflare-mcp/tests/index.test.ts b/dev-packages/e2e-tests/test-applications/cloudflare-mcp/tests/index.test.ts index 22098b605de8..84236339babf 100644 --- a/dev-packages/e2e-tests/test-applications/cloudflare-mcp/tests/index.test.ts +++ b/dev-packages/e2e-tests/test-applications/cloudflare-mcp/tests/index.test.ts @@ -94,7 +94,8 @@ test('sends spans for MCP 2026-07-28 tool calls', async ({ baseURL }) => { expect(requestTrace?.data?.['http.request.body.size']).toBe(341); expect(requestTrace?.data?.['user_agent.original']).toBe('node'); expect(requestTrace?.data?.['http.request.header.content_type']).toBe('application/json'); - expect(requestTrace?.data?.['network.protocol.name']).toBe('HTTP/1.1'); + expect(requestTrace?.data?.['network.protocol.name']).toBe('http'); + expect(requestTrace?.data?.['network.protocol.version']).toBe('1.1'); expect(requestTrace?.data?.['http.response.status_code']).toBe(200); expect(requestTrace?.data?.['mcp.server.extra']).toBe(' /|\ ^._.^ /|\ '); expect(mcpTrace?.trace_id).toBe(requestTrace?.trace_id); diff --git a/dev-packages/e2e-tests/test-applications/deno-streamed/tests/spans.test.ts b/dev-packages/e2e-tests/test-applications/deno-streamed/tests/spans.test.ts index e79589dcac76..cb765ed3f41d 100644 --- a/dev-packages/e2e-tests/test-applications/deno-streamed/tests/spans.test.ts +++ b/dev-packages/e2e-tests/test-applications/deno-streamed/tests/spans.test.ts @@ -67,6 +67,10 @@ const SEGMENT_SPAN = { type: 'integer', value: expect.any(Number), }, + 'network.protocol.name': { + type: 'string', + value: 'http', + }, 'os.name': { type: 'string', value: expect.any(String), diff --git a/dev-packages/e2e-tests/test-applications/hono-4/tests/constants.ts b/dev-packages/e2e-tests/test-applications/hono-4/tests/constants.ts index bb58543dc06f..0bd38ea85aa3 100644 --- a/dev-packages/e2e-tests/test-applications/hono-4/tests/constants.ts +++ b/dev-packages/e2e-tests/test-applications/hono-4/tests/constants.ts @@ -1,5 +1,5 @@ export type Runtime = 'cloudflare' | 'node' | 'bun' | 'deno'; -export const RUNTIME = (process.env.RUNTIME || 'deno') as Runtime; +export const RUNTIME = (process.env.RUNTIME || 'node') as Runtime; export const APP_NAME = 'hono-4'; diff --git a/dev-packages/e2e-tests/test-applications/hono-4/tests/tracing.test.ts b/dev-packages/e2e-tests/test-applications/hono-4/tests/tracing.test.ts index 5f159ec2dbf8..2e2d8aa02c85 100644 --- a/dev-packages/e2e-tests/test-applications/hono-4/tests/tracing.test.ts +++ b/dev-packages/e2e-tests/test-applications/hono-4/tests/tracing.test.ts @@ -74,7 +74,7 @@ test('attaches HTTP connection info to the server transaction', async ({ baseURL // Regression guard against connection info attributes. // The conninfo middleware must only *add* attributes, never replace or clear existing ones. // These are the baseline attributes the server transaction carries *without* the conninfo feature -test("preserves the baseline client.* and network.* server span attributes that the SDK sends without Hono's conninfo", async ({ +test("preserves the baseline server.*, client.* and network.* server span attributes that the SDK sends without Hono's conninfo", async ({ baseURL, }) => { const transactionPromise = waitForTransaction(APP_NAME, event => { @@ -88,18 +88,38 @@ test("preserves the baseline client.* and network.* server span attributes that const data = transaction.contexts?.trace?.data ?? {}; if (RUNTIME === 'node') { - expect(data['net.host.name']).toBe('localhost'); - expect(data['net.transport']).toBe('ip_tcp'); - expect(data['net.host.ip']).toEqual(expect.any(String)); - expect(data['net.peer.ip']).toEqual(expect.any(String)); - expect(data['net.peer.port']).toEqual(expect.any(Number)); + expect(data['server.address']).toBe('localhost'); + expect(data['server.port']).toBe(Number(new URL(baseURL!).port)); + expect(data['client.address']).toEqual(expect.any(String)); + expect(data['client.port']).toEqual(expect.any(Number)); + expect(data['network.type']).toMatch(/^ipv[46]$/); + expect(data['network.protocol.name']).toBe('http'); + expect(data['network.protocol.version']).toBe('1.1'); + expect(data['network.transport']).toBeUndefined(); + expect(data['network.local.port']).toBe(data['server.port']); + expect(data['network.local.address']).toEqual(expect.any(String)); + expect(data['network.peer.address']).toBe(data['client.address']); + expect(data['network.peer.port']).toBe(data['client.port']); } else if (RUNTIME === 'bun') { - // Doesn't set net.*, network.*, or client.* attributes + expect(data['client.address']).toEqual(expect.any(String)); + expect(data['client.port']).toEqual(expect.any(Number)); + expect(data['network.peer.address']).toBe(data['client.address']); + expect(data['network.peer.port']).toBe(data['client.port']); + expect(data['network.type']).toMatch(/^ipv[46]$/); } else if (RUNTIME === 'cloudflare') { - expect(data['network.protocol.name']).toBe('HTTP/1.1'); + expect(data['server.address']).toBe('localhost'); + expect(data['client.address']).toBe('::1'); + expect(data['network.peer.address']).toBe(data['client.address']); + expect(data['network.protocol.name']).toBe('http'); + expect(data['network.protocol.version']).toBe('1.1'); } else if (RUNTIME === 'deno') { + expect(data['server.address']).toBe('localhost'); expect(data['client.address']).toEqual(expect.any(String)); expect(data['client.port']).toEqual(expect.any(Number)); + expect(data['network.peer.address']).toBe(data['client.address']); + expect(data['network.peer.port']).toBe(data['client.port']); + expect(data['network.transport']).toBe('tcp'); + expect(data['network.protocol.name']).toBe('http'); } else { throw new Error(`No tests for runtime: ${RUNTIME}`); } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts index b6eac56cc0a0..d1e96aa3250e 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-11/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts index 03593be28685..fe325e4408fb 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-8/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts index 5f1a79b1d8eb..bce6acc1589a 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/transactions.test.ts @@ -50,17 +50,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts index fba209a9b966..aae5014d3366 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/tests/propagation.test.ts @@ -65,17 +65,22 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-http/${id}`, 'http.user_agent': expect.any(String), 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-http/:id', @@ -104,16 +109,21 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', @@ -194,17 +204,22 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-fetch/${id}`, 'http.user_agent': expect.any(String), 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-fetch/:id', @@ -233,16 +248,21 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts index 723c2befcdaa..b2e6183942b6 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-fastify/tests/transactions.test.ts @@ -28,17 +28,22 @@ test.skip('Sends an API route transaction', async ({ baseURL }) => { 'http.response.status_code': 200, 'url.full': 'http://localhost:3030/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts index 27a666af610c..63acafb5f5c7 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction from module', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/example-module/transaction', 'url.path': '/example-module/transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/example-module/transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/example-module/transaction', diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts index 1d29fdfad9a7..6027586c497f 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction from module', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/example-module/transaction', 'url.path': '/example-module/transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/example-module/transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/example-module/transaction', diff --git a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts index c822c7ffaef9..e45fa3547f49 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/middleware.test.ts @@ -74,7 +74,8 @@ test('Should trace outgoing fetch requests inside middleware and create breadcru 'http.response.status_code': 200, type: 'fetch', 'url.full': 'http://localhost:3030/', - 'server.address': 'localhost:3030', + 'server.address': 'localhost', + 'server.port': 3030, 'sentry.op': 'http.client', 'sentry.origin': 'auto.http.wintercg_fetch', }, diff --git a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/tests/server.test.ts b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/tests/server.test.ts index 54c6a412038c..f3fb420bdf00 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-esm-loader/tests/server.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-esm-loader/tests/server.test.ts @@ -45,12 +45,12 @@ test('Should record a transaction for route with parameters', async ({ request } 'http.target': '/test-transaction/1', 'url.full': 'http://localhost:3030/test-transaction/1', 'http.user_agent': expect.any(String), - 'net.host.ip': expect.any(String), - 'net.host.name': 'localhost', - 'net.host.port': 3030, - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), - 'net.transport': 'ip_tcp', + 'network.local.address': expect.any(String), + 'server.address': 'localhost', + 'network.local.port': 3030, + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.transport': 'tcp', 'sentry.kind': 'server', 'sentry.op': 'http.server', 'sentry.origin': 'auto.http.otel.http', diff --git a/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts index e3a7944dc28a..092667f79a4b 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-v5/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts index 8629fefe2efb..231e64954da4 100644 --- a/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts index abda01da852d..34dc29cb8b6d 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/propagation.test.ts @@ -65,17 +65,22 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-http/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-http/:id', @@ -104,16 +109,21 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', @@ -194,17 +204,22 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-fetch/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-fetch/:id', @@ -233,16 +248,21 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.user_agent': 'node', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts index 281d1028678c..9fb13b3e6973 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-3/tests/transactions.test.ts @@ -29,17 +29,22 @@ test.skip('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts index 63c198a954bb..8ee2382eab61 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/propagation.test.ts @@ -65,17 +65,22 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-http/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-http/:id', @@ -104,16 +109,21 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', @@ -194,17 +204,22 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-fetch/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-fetch/:id', @@ -233,16 +248,21 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts index 662ece5f348a..4156910cd152 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-4/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts index 94014c521af5..fb5dab4a0dcb 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/propagation.test.ts @@ -65,17 +65,22 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-http/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-http/:id', @@ -104,16 +109,21 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', @@ -194,17 +204,22 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-fetch/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-fetch/:id', @@ -233,16 +248,21 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.user_agent': 'node', diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts index ec871f134b42..37243a793771 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts index 69c7c470db20..8eea53d68454 100644 --- a/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-hapi/tests/transactions.test.ts @@ -23,17 +23,22 @@ test('Sends successful transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-success', 'url.path': '/test-success', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-success', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-success', diff --git a/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts index b86df1bcfa7c..fe65fde61d4c 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-koa/tests/propagation.test.ts @@ -64,17 +64,22 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-http/${id}`, 'url.path': `/test-outgoing-http/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-http/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-http/:id', @@ -103,16 +108,21 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', @@ -193,17 +203,22 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-outgoing-fetch/${id}`, 'url.path': `/test-outgoing-fetch/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-outgoing-fetch/${id}`, 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-outgoing-fetch/:id', @@ -232,16 +247,21 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { 'url.full': `http://localhost:3030/test-inbound-headers/${id}`, 'url.path': `/test-inbound-headers/${id}`, 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': `/test-inbound-headers/${id}`, 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-inbound-headers/:id', diff --git a/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts index 4749feefddb1..c32dd76dbbfe 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-koa/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts index b86a86f6adc8..49f520d27707 100644 --- a/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/tsx-express/tests/transactions.test.ts @@ -24,17 +24,22 @@ test('Sends an API route transaction', async ({ baseURL }) => { 'url.full': 'http://localhost:3030/test-transaction', 'url.path': '/test-transaction', 'http.host': 'localhost:3030', - 'net.host.name': 'localhost', + 'server.address': 'localhost', 'http.method': 'GET', 'http.scheme': 'http', 'http.target': '/test-transaction', 'http.user_agent': 'node', 'http.flavor': '1.1', - 'net.transport': 'ip_tcp', - 'net.host.ip': expect.any(String), - 'net.host.port': expect.any(Number), - 'net.peer.ip': expect.any(String), - 'net.peer.port': expect.any(Number), + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.transport': 'tcp', + 'network.local.address': expect.any(String), + 'network.local.port': expect.any(Number), + 'network.peer.address': expect.any(String), + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'server.port': 3030, 'http.status_code': 200, 'http.status_text': 'OK', 'http.route': '/test-transaction', diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts index 89b93622cce1..901c4d9229c1 100644 --- a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts @@ -36,10 +36,10 @@ describe('outgoing http spans - strip query', () => { 'http.response_content_length_uncompressed': 0, 'http.status_code': 200, 'http.status_text': 'OK', - 'net.peer.ip': '::1', - 'net.peer.name': 'localhost', - 'net.peer.port': expect.any(Number), - 'net.transport': 'ip_tcp', + 'network.peer.address': '::1', + 'server.address': 'localhost', + 'network.peer.port': expect.any(Number), + 'network.transport': 'tcp', 'sentry.kind': 'client', 'sentry.op': 'http.client', 'sentry.origin': 'auto.http.client', diff --git a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts index e1053a706d16..8357f50daa4c 100644 --- a/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts @@ -76,12 +76,17 @@ describe('httpIntegration', () => { 'http.status_text': 'OK', 'http.target': '/test?a=1&b=2', 'http.user_agent': 'node', - 'net.host.ip': '::1', - 'net.host.name': 'localhost', - 'net.host.port': port, - 'net.peer.ip': '::1', - 'net.peer.port': expect.any(Number), - 'net.transport': 'ip_tcp', + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.local.address': '::1', + 'server.address': 'localhost', + 'server.port': port, + 'network.local.port': port, + 'network.peer.address': '::1', + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'network.transport': 'tcp', 'sentry.kind': 'server', 'sentry.op': 'http.server', 'sentry.origin': 'auto.http.otel.http', @@ -118,12 +123,17 @@ describe('httpIntegration', () => { 'http.status_text': 'OK', 'http.target': '/test?a=1&b=2', 'http.user_agent': 'node', - 'net.host.ip': '::1', - 'net.host.name': 'localhost', - 'net.host.port': port, - 'net.peer.ip': '::1', - 'net.peer.port': expect.any(Number), - 'net.transport': 'ip_tcp', + 'client.address': '::1', + 'client.port': expect.any(Number), + 'network.local.address': '::1', + 'server.address': 'localhost', + 'server.port': port, + 'network.local.port': port, + 'network.peer.address': '::1', + 'network.peer.port': expect.any(Number), + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', + 'network.transport': 'tcp', 'sentry.kind': 'server', 'sentry.op': 'http.server', 'sentry.origin': 'auto.http.otel.http', diff --git a/docs/migration/v11-end-state.md b/docs/migration/v11-end-state.md index bb6c5a469407..224e83e3cba4 100644 --- a/docs/migration/v11-end-state.md +++ b/docs/migration/v11-end-state.md @@ -582,11 +582,39 @@ String and regular-expression matching for `tracePropagationTargets` is now case Affected SDKs: All SDKs. -- The `http.query` and `http.fragment` span attributes were renamed to `url.query` and `url.fragment`. -- The `net.peer.name` and `net.peer.port` span attributes on database and messaging client spans were replaced by `server.address` and `server.port`, and `net.transport` by `network.transport`. -- `network.*` span attributes were aligned across SDKs. +If you reference these attributes in custom instrumentation, `beforeSendSpan`, dashboards, or alerts, update them to the new names. + +#### URL attributes + +The `http.query` and `http.fragment` span attributes were renamed to `url.query` and `url.fragment`. + +#### Network attributes + +Network-related span attributes now use the current Sentry semantic conventions, aligned across SDKs. If you query, transform, or alert on the legacy `net.*` fields, update those references: + +| v10 attribute | v11 attribute | +| --------------- | ----------------------- | +| `net.host.name` | `server.address` | +| `net.host.ip` | `network.local.address` | +| `net.host.port` | `network.local.port` | +| `net.peer.name` | `server.address` | +| `net.peer.ip` | `network.peer.address` | +| `net.peer.port` | `network.peer.port` | +| `net.transport` | `network.transport` | + +On database and messaging client spans, `net.peer.name` and `net.peer.port` were replaced by `server.address` and `server.port`. + +Transport values also change from `ip_tcp` and `ip_udp` to `tcp` and `udp`. HTTP instrumentation reports the application protocol as `network.protocol.name: "http"` and reports its version separately in `network.protocol.version`. + +Attribute availability remains runtime-dependent. For example, browser and Worker APIs do not expose socket peer details, so those spans only include the network information their runtime provides. Client IP address collection remains controlled by `dataCollection.userInfo` where the runtime exposes it. + +#### Messaging and database attributes + - Legacy messaging (`messaging.*`) span attributes on the AMQP instrumentation were replaced by their current semantic-convention equivalents. - The database span attributes `db.system`, `db.name`, `db.operation`, `db.statement` and `db.mongodb.collection` were renamed to `db.system.name`, `db.namespace`, `db.operation.name`, `db.query.text` and `db.collection.name`. + +#### GenAI attributes + - The gen_ai cache token attributes `gen_ai.usage.cache_creation_input_tokens` and `gen_ai.usage.cache_read_input_tokens` were renamed to `gen_ai.usage.cache_creation.input_tokens` and `gen_ai.usage.cache_read.input_tokens`. - The `gen_ai.system` span attribute was renamed to `gen_ai.provider.name` across all AI integrations. - The `gen_ai.request.available_tools` span attribute was renamed to `gen_ai.tool.definitions` across all AI integrations. @@ -596,11 +624,16 @@ Affected SDKs: All SDKs. - The deprecated `gen_ai.tool.type` span attribute is no longer set on tool spans. - The `ai.pipeline.name` and `ai.streaming` span attributes on Vercel AI spans were renamed to `gen_ai.pipeline.name` and `gen_ai.response.streaming`. - The `gen_ai.prompt` span attribute is no longer set by the Anthropic integration. The legacy Completions API's `prompt` is now reported as a user message on `gen_ai.input.messages`, like every other request shape. + +#### Other attributes + - The `code.filepath` and `code.function` span attributes on `ui.long_animation_frame` spans were renamed to `code.file.path` and `code.function.name`. - The `fs_error` span attribute on `file` spans was replaced by `error.type`. The value changed from the full error message to just the syscall's error code instead (`ENOENT`). -- Span attributes now use the shared `@sentry/conventions` package under the hood. -If you reference these attributes in custom instrumentation, `beforeSendSpan`, dashboards, or alerts, update them to the new names. +#### Attribute constants + +Span attributes now use the shared `@sentry/conventions` package under the hood. +The deprecated `semanticAttributes` re-export was removed. Import span attribute constants from `@sentry/core` directly. ### Span operation (`op`) changes @@ -918,10 +951,6 @@ Sentry.init({ - `getSentryResource` was removed. - OpenTelemetry resources are no longer collected, and `contexts.otel.resource` was dropped from events. As a result, the `OTEL_SERVICE_NAME` and `OTEL_RESOURCE_ATTRIBUTES` environment variables are no longer read by the SDK. -### `@sentry/core` span attributes - -- The deprecated `semanticAttributes` re-export was removed. Import span attribute constants from `@sentry/core` directly. - ### AI integrations - The `enableTruncation` and `streamGenAiSpans` flags were removed. The new default is no truncation and to always stream gen AI spans. diff --git a/packages/cloudflare/src/request.ts b/packages/cloudflare/src/request.ts index 4f7e2fbbe916..07d5435e4084 100644 --- a/packages/cloudflare/src/request.ts +++ b/packages/cloudflare/src/request.ts @@ -1,4 +1,5 @@ import type { CfProperties, IncomingRequestCfProperties } from '@cloudflare/workers-types'; +import { NETWORK_PROTOCOL_NAME, NETWORK_PROTOCOL_VERSION } from '@sentry/conventions/attributes'; import { captureException, continueTrace, @@ -121,7 +122,9 @@ export function wrapRequestHandlerWithInit( addCultureContext(isolationScope, request.cf); if (typeof request.cf.httpProtocol === 'string') { - attributes['network.protocol.name'] = request.cf.httpProtocol; + const [protocolName, protocolVersion] = request.cf.httpProtocol.toLowerCase().split('/'); + attributes[NETWORK_PROTOCOL_NAME] = protocolName; + attributes[NETWORK_PROTOCOL_VERSION] = protocolVersion; } } diff --git a/packages/cloudflare/test/request.test.ts b/packages/cloudflare/test/request.test.ts index 61f43e7c91e7..44587f6224de 100644 --- a/packages/cloudflare/test/request.test.ts +++ b/packages/cloudflare/test/request.test.ts @@ -598,7 +598,8 @@ describe('withSentry', () => { 'http.request.method': 'GET', 'url.full': 'https://example.com/', 'server.address': 'example.com', - 'network.protocol.name': 'HTTP/1.1', + 'network.protocol.name': 'http', + 'network.protocol.version': '1.1', 'url.scheme': 'https:', 'url.path': '/', 'sentry.sample_rate': 1, diff --git a/packages/core/src/fetch.ts b/packages/core/src/fetch.ts index cfcba668dac5..1e414aa9c226 100644 --- a/packages/core/src/fetch.ts +++ b/packages/core/src/fetch.ts @@ -1,5 +1,12 @@ /* eslint-disable max-lines */ -import { HTTP_METHOD, SERVER_ADDRESS, URL_FRAGMENT, URL_FULL, URL_QUERY } from '@sentry/conventions/attributes'; +import { + HTTP_METHOD, + SERVER_ADDRESS, + SERVER_PORT, + URL_FRAGMENT, + URL_FULL, + URL_QUERY, +} from '@sentry/conventions/attributes'; import type { Client } from './client'; import { getClient } from './currentScopes'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from './semanticAttributes'; @@ -365,7 +372,8 @@ function getFetchSpanAttributes( if (parsedUrl) { if (!isURLObjectRelative(parsedUrl)) { attributes[URL_FULL] = filterCollectedUrl(stripDataUrlContent(parsedUrl.href), client); - attributes[SERVER_ADDRESS] = parsedUrl.host; + attributes[SERVER_ADDRESS] = parsedUrl.hostname; + attributes[SERVER_PORT] = parsedUrl.port ? Number(parsedUrl.port) : undefined; } attributes[URL_QUERY] = filterCollectedUrlQuery(getUrlQuery(parsedUrl.search), client); attributes[URL_FRAGMENT] = getUrlFragment(parsedUrl.hash); diff --git a/packages/core/src/integrations/http/get-outgoing-span-data.ts b/packages/core/src/integrations/http/get-outgoing-span-data.ts index 96a6d8812919..7ca1a4f64f17 100644 --- a/packages/core/src/integrations/http/get-outgoing-span-data.ts +++ b/packages/core/src/integrations/http/get-outgoing-span-data.ts @@ -9,7 +9,15 @@ import { HTTP_HOST, HTTP_METHOD, HTTP_TARGET, - NET_PEER_NAME, + NETWORK_LOCAL_ADDRESS, + NETWORK_LOCAL_PORT, + NETWORK_PEER_ADDRESS, + NETWORK_PEER_PORT, + NETWORK_PROTOCOL_NAME, + NETWORK_PROTOCOL_VERSION, + NETWORK_TRANSPORT, + SERVER_ADDRESS, + SERVER_PORT, SENTRY_KIND, URL_FULL, USER_AGENT_ORIGINAL, @@ -41,7 +49,8 @@ export function getOutgoingRequestSpanData(request: HttpClientRequest): StartSpa /* eslint-disable typescript/no-deprecated */ [HTTP_METHOD]: request.method, [HTTP_TARGET]: filterCollectedUrl(request.path || '/'), - [NET_PEER_NAME]: request.host, + [SERVER_ADDRESS]: request.host, + [SERVER_PORT]: typeof request.port === 'number' && !isNaN(request.port) ? request.port : undefined, [HTTP_HOST]: request.getHeader('host') as string | undefined, /* eslint-enable typescript/no-deprecated */ [USER_AGENT_ORIGINAL]: userAgent || undefined, @@ -56,16 +65,16 @@ export function getOutgoingRequestSpanData(request: HttpClientRequest): StartSpa */ export function setIncomingResponseSpanData(response: HttpIncomingMessage, span: Span): void { const { statusCode, statusMessage, httpVersion, socket } = response; - const transport = httpVersion?.toUpperCase() !== 'QUIC' ? 'ip_tcp' : 'ip_udp'; + const transport = httpVersion?.toUpperCase() !== 'QUIC' ? 'tcp' : 'udp'; span.setAttributes({ 'http.response.status_code': statusCode, - 'network.protocol.version': httpVersion, + [NETWORK_PROTOCOL_NAME]: 'http', + [NETWORK_PROTOCOL_VERSION]: httpVersion, // TODO(v11): Update these to the Sentry semantic attributes for urls. // https://getsentry.github.io/sentry-conventions/attributes/ 'http.flavor': httpVersion, - 'network.transport': transport, - 'net.transport': transport, + [NETWORK_TRANSPORT]: transport, 'http.status_text': statusMessage?.toUpperCase(), 'http.status_code': statusCode, ...getResponseContentLengthAttributes(response), @@ -75,12 +84,12 @@ export function setIncomingResponseSpanData(response: HttpIncomingMessage, span: function getSocketAttrs(socket: HttpIncomingMessage['socket']): SpanAttributes { if (!socket) return {}; - const { remoteAddress, remotePort } = socket; + const { localAddress, localPort, remoteAddress, remotePort } = socket; return { - 'network.peer.address': remoteAddress, - 'network.peer.port': remotePort, - 'net.peer.ip': remoteAddress, - 'net.peer.port': remotePort, + [NETWORK_LOCAL_ADDRESS]: localAddress, + [NETWORK_LOCAL_PORT]: localPort, + [NETWORK_PEER_ADDRESS]: remoteAddress, + [NETWORK_PEER_PORT]: remotePort, }; } diff --git a/packages/core/src/integrations/http/server-subscription.ts b/packages/core/src/integrations/http/server-subscription.ts index ee7f09ab47d4..b4d3839c877d 100644 --- a/packages/core/src/integrations/http/server-subscription.ts +++ b/packages/core/src/integrations/http/server-subscription.ts @@ -40,7 +40,22 @@ import { import { safeMathRandom } from '../../utils/randomSafeContext'; import type { SpanAttributes } from '../../types/span'; import type { SpanStatus } from '../../types/spanStatus'; -import { URL_FULL, URL_PATH, SENTRY_KIND } from '@sentry/conventions/attributes'; +import { + CLIENT_ADDRESS, + CLIENT_PORT, + NETWORK_LOCAL_ADDRESS, + NETWORK_LOCAL_PORT, + NETWORK_PEER_ADDRESS, + NETWORK_PEER_PORT, + NETWORK_PROTOCOL_NAME, + NETWORK_PROTOCOL_VERSION, + NETWORK_TRANSPORT, + SERVER_ADDRESS, + SERVER_PORT, + URL_FULL, + URL_PATH, + SENTRY_KIND, +} from '@sentry/conventions/attributes'; import { filterCollectedUrl } from '../../utils/data-collection/filterCollectedUrl'; // Tree-shakable guard to remove all code related to tracing @@ -282,6 +297,10 @@ function buildServerSpanWrap( const scheme = fullUrl.startsWith('https') ? 'https' : 'http'; const { socket } = request; const { localAddress, localPort, remoteAddress, remotePort } = socket ?? {}; + const collectClientAddress = client.getDataCollectionOptions().userInfo; + // `client.address` is the originating client, so a forwarding header wins over the socket, which + // behind a proxy holds the proxy's address. `network.peer.address` keeps the socket value. + const clientAddress = getForwardedClientAddress(ips) ?? remoteAddress; return startSpanManual( { @@ -293,10 +312,14 @@ function buildServerSpanWrap( [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', [SENTRY_KIND]: 'server', // Network attributes - 'net.host.ip': localAddress, - 'net.host.port': localPort, - 'net.peer.ip': remoteAddress, - 'net.peer.port': remotePort, + [SERVER_ADDRESS]: hostname, + [SERVER_PORT]: localPort, + [NETWORK_LOCAL_ADDRESS]: localAddress, + [NETWORK_LOCAL_PORT]: localPort, + [CLIENT_ADDRESS]: collectClientAddress ? clientAddress : undefined, + [CLIENT_PORT]: remotePort, + [NETWORK_PEER_ADDRESS]: collectClientAddress ? remoteAddress : undefined, + [NETWORK_PEER_PORT]: remotePort, 'sentry.http.prefetch': isKnownPrefetchRequest(request) || undefined, // Old Semantic Conventions attributes for compatibility [URL_FULL]: filterCollectedUrl(fullUrl, client), @@ -307,12 +330,13 @@ function buildServerSpanWrap( client, ), 'http.host': host, - 'net.host.name': hostname, - 'http.client_ip': typeof ips === 'string' ? ips.split(',')[0] : undefined, + [NETWORK_PROTOCOL_NAME]: 'http', + [NETWORK_PROTOCOL_VERSION]: httpVersion, + 'http.client_ip': collectClientAddress ? getForwardedClientAddress(ips) : undefined, 'http.user_agent': userAgent, 'http.scheme': scheme, 'http.flavor': httpVersion, - 'net.transport': httpVersion?.toUpperCase() === 'QUIC' ? 'ip_udp' : 'ip_tcp', + [NETWORK_TRANSPORT]: httpVersion?.toUpperCase() === 'QUIC' ? 'udp' : 'tcp', ...getRequestContentLengthAttribute(request), ...httpHeadersToSpanAttributes(normalizedRequest.headers || {}, dataCollectionOptions), }, @@ -359,6 +383,14 @@ function buildServerSpanWrap( }; } +/** + * First entry of `X-Forwarded-For`: the client as seen by the outermost proxy. + * https://opentelemetry.io/docs/specs/semconv/registry/attributes/client/#client-address + */ +function getForwardedClientAddress(forwardedFor: string | string[] | undefined): string | undefined { + return typeof forwardedFor === 'string' ? forwardedFor.split(',')[0]?.trim() || undefined : undefined; +} + function shouldIgnoreSpansForIncomingRequest( request: HttpIncomingMessage, { diff --git a/packages/core/test/lib/integrations/http/get-outgoing-span-data.test.ts b/packages/core/test/lib/integrations/http/get-outgoing-span-data.test.ts index 90b3b1e06744..72c8b22aa0e6 100644 --- a/packages/core/test/lib/integrations/http/get-outgoing-span-data.test.ts +++ b/packages/core/test/lib/integrations/http/get-outgoing-span-data.test.ts @@ -5,7 +5,18 @@ import { } from '../../../../src/integrations/http/get-outgoing-span-data'; import type { HttpClientRequest, HttpIncomingMessage } from '../../../../src/integrations/http/types'; import type { Span } from '../../../../src/types/span'; -import { HTTP_METHOD, HTTP_TARGET, NET_PEER_NAME, URL_FULL } from '@sentry/conventions/attributes'; +import { + HTTP_METHOD, + HTTP_TARGET, + NETWORK_LOCAL_ADDRESS, + NETWORK_LOCAL_PORT, + NETWORK_PEER_ADDRESS, + NETWORK_PEER_PORT, + NETWORK_TRANSPORT, + SERVER_ADDRESS, + SERVER_PORT, + URL_FULL, +} from '@sentry/conventions/attributes'; function makeMockRequest(overrides: Partial> = {}): HttpClientRequest { return { @@ -65,13 +76,14 @@ describe('getOutgoingRequestSpanData', () => { expect(result.name).toMatch(/^POST /); }); - it('includes URL_FULL, HTTP_METHOD, HTTP_TARGET, NET_PEER_NAME', () => { + it('includes URL_FULL, HTTP_METHOD, HTTP_TARGET, and server endpoint attributes', () => { const result = getOutgoingRequestSpanData(makeMockRequest()); expect(result.attributes).toMatchObject({ [URL_FULL]: 'http://example.com/api/test', [HTTP_METHOD]: 'GET', [HTTP_TARGET]: '/api/test', - [NET_PEER_NAME]: 'example.com', + [SERVER_ADDRESS]: 'example.com', + [SERVER_PORT]: 80, }); }); @@ -124,20 +136,16 @@ describe('setIncomingResponseSpanData', () => { expect(span.setAttributes).toHaveBeenCalledWith(expect.objectContaining({ 'http.status_text': 'CREATED' })); }); - it('uses ip_tcp transport for non-QUIC connections', () => { + it('uses tcp transport for non-QUIC connections', () => { const span = makeMockSpan(); setIncomingResponseSpanData(makeMockResponse({ httpVersion: '1.1' }), span); - expect(span.setAttributes).toHaveBeenCalledWith( - expect.objectContaining({ 'network.transport': 'ip_tcp', 'net.transport': 'ip_tcp' }), - ); + expect(span.setAttributes).toHaveBeenCalledWith(expect.objectContaining({ [NETWORK_TRANSPORT]: 'tcp' })); }); - it('uses ip_udp transport for QUIC connections', () => { + it('uses udp transport for QUIC connections', () => { const span = makeMockSpan(); setIncomingResponseSpanData(makeMockResponse({ httpVersion: 'QUIC' }), span); - expect(span.setAttributes).toHaveBeenCalledWith( - expect.objectContaining({ 'network.transport': 'ip_udp', 'net.transport': 'ip_udp' }), - ); + expect(span.setAttributes).toHaveBeenCalledWith(expect.objectContaining({ [NETWORK_TRANSPORT]: 'udp' })); }); it('includes socket address and port attributes when socket is present', () => { @@ -148,10 +156,10 @@ describe('setIncomingResponseSpanData', () => { setIncomingResponseSpanData(response, span); expect(span.setAttributes).toHaveBeenCalledWith( expect.objectContaining({ - 'network.peer.address': '1.2.3.4', - 'network.peer.port': 12345, - 'net.peer.ip': '1.2.3.4', - 'net.peer.port': 12345, + [NETWORK_LOCAL_ADDRESS]: undefined, + [NETWORK_LOCAL_PORT]: undefined, + [NETWORK_PEER_ADDRESS]: '1.2.3.4', + [NETWORK_PEER_PORT]: 12345, }), ); }); diff --git a/packages/core/test/lib/integrations/http/server-subscription.test.ts b/packages/core/test/lib/integrations/http/server-subscription.test.ts index 153e853ce56b..f957422885b0 100644 --- a/packages/core/test/lib/integrations/http/server-subscription.test.ts +++ b/packages/core/test/lib/integrations/http/server-subscription.test.ts @@ -1,4 +1,18 @@ -import { URL_FULL, URL_PATH } from '@sentry/conventions/attributes'; +import { + CLIENT_ADDRESS, + CLIENT_PORT, + NETWORK_LOCAL_ADDRESS, + NETWORK_LOCAL_PORT, + NETWORK_PEER_ADDRESS, + NETWORK_PEER_PORT, + NETWORK_PROTOCOL_NAME, + NETWORK_PROTOCOL_VERSION, + NETWORK_TRANSPORT, + SERVER_ADDRESS, + SERVER_PORT, + URL_FULL, + URL_PATH, +} from '@sentry/conventions/attributes'; import * as http from 'node:http'; import type { AddressInfo } from 'node:net'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -41,7 +55,11 @@ describe('getHttpServerSubscriptions', () => { await new Promise(resolve => server.close(() => resolve())); }); - async function makeRequest(path: string, method: 'GET' | 'HEAD' | 'OPTIONS' = 'GET'): Promise { + async function makeRequest( + path: string, + method: 'GET' | 'HEAD' | 'OPTIONS' = 'GET', + extraHeaders: Record = {}, + ): Promise { const { port } = server.address() as AddressInfo; return new Promise((resolve, reject) => { // Connection: close so the server-side `response.once('close', ...)` @@ -53,7 +71,7 @@ describe('getHttpServerSubscriptions', () => { port, path, method, - headers: { Connection: 'close' }, + headers: { Connection: 'close', ...extraHeaders }, }, res => { // throw away response body @@ -109,11 +127,76 @@ describe('getHttpServerSubscriptions', () => { 'sentry.source': 'url', [URL_FULL]: expect.stringMatching(/\/users\/42\?foo=bar$/), [URL_PATH]: '/users/42', + [SERVER_ADDRESS]: '127.0.0.1', + [SERVER_PORT]: expect.any(Number), + [NETWORK_LOCAL_ADDRESS]: '127.0.0.1', + [NETWORK_LOCAL_PORT]: expect.any(Number), + [CLIENT_ADDRESS]: '127.0.0.1', + [CLIENT_PORT]: expect.any(Number), + [NETWORK_PEER_ADDRESS]: '127.0.0.1', + [NETWORK_PEER_PORT]: expect.any(Number), + [NETWORK_PROTOCOL_NAME]: 'http', + [NETWORK_PROTOCOL_VERSION]: '1.1', + [NETWORK_TRANSPORT]: 'tcp', }), }), ); }); + it('prefers the forwarded client over the socket for `client.address`', async () => { + server = http.createServer((_req, res) => res.end('ok')); + await new Promise(resolve => server.listen(0, '127.0.0.1', () => resolve())); + instrument(true); + + await makeRequest('/users/42', 'GET', { 'X-Forwarded-For': '203.0.113.7, 198.51.100.1' }); + const transaction = await waitForTransaction(); + + expect(transaction.contexts?.trace?.data).toEqual( + expect.objectContaining({ + // the originating client, as reported by the outermost proxy + [CLIENT_ADDRESS]: '203.0.113.7', + // the immediate peer stays the socket, i.e. the proxy itself + [NETWORK_PEER_ADDRESS]: '127.0.0.1', + }), + ); + }); + + it('does not report a forwarded client address when userInfo collection is disabled', async () => { + client = new TestClient(getDefaultTestClientOptions({ tracesSampleRate: 1, dataCollection: { userInfo: false } })); + const originalSendEvent = client.sendEvent.bind(client); + client.sendEvent = (event, hint) => { + events.push(event); + return originalSendEvent(event, hint); + }; + setCurrentClient(client); + client.init(); + getIsolationScope().setClient(client); + + server = http.createServer((_req, res) => res.end('ok')); + await new Promise(resolve => server.listen(0, '127.0.0.1', () => resolve())); + instrument(true); + + await makeRequest('/users/42', 'GET', { 'X-Forwarded-For': '203.0.113.7' }); + const transaction = await waitForTransaction(); + + const data = transaction.contexts?.trace?.data; + expect(data).not.toHaveProperty(CLIENT_ADDRESS); + expect(data).not.toHaveProperty(NETWORK_PEER_ADDRESS); + // the deprecated alias of `client.address` carries the same IP, so it has to be gated too + expect(data).not.toHaveProperty('http.client_ip'); + }); + + it('reports the forwarded client address on the deprecated `http.client_ip` alias too', async () => { + server = http.createServer((_req, res) => res.end('ok')); + await new Promise(resolve => server.listen(0, '127.0.0.1', () => resolve())); + instrument(true); + + await makeRequest('/users/42', 'GET', { 'X-Forwarded-For': '203.0.113.7, 198.51.100.1' }); + const transaction = await waitForTransaction(); + + expect(transaction.contexts?.trace?.data).toEqual(expect.objectContaining({ 'http.client_ip': '203.0.113.7' })); + }); + // `http.target` is the deprecated alias of `url.full` and carries the same query string, so it has to // respect `dataCollection.urlQueryParams` too. it('filters sensitive query params in `http.target` and `url.full`', async () => { diff --git a/packages/deno/package.json b/packages/deno/package.json index af49fbb46874..30a68d5e2a68 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -28,6 +28,7 @@ ], "dependencies": { "@opentelemetry/api": "^1.9.1", + "@sentry/conventions": "^0.19.0", "@sentry/core": "10.67.0", "@sentry/server-utils": "10.67.0" }, diff --git a/packages/deno/src/wrap-deno-request-handler.ts b/packages/deno/src/wrap-deno-request-handler.ts index c71c950b3d30..004a5f9fa26d 100644 --- a/packages/deno/src/wrap-deno-request-handler.ts +++ b/packages/deno/src/wrap-deno-request-handler.ts @@ -1,3 +1,4 @@ +import { CLIENT_ADDRESS, CLIENT_PORT, NETWORK_PROTOCOL_NAME } from '@sentry/conventions/attributes'; import type { Integration, MaxRequestBodySize } from '@sentry/core'; import { captureBodyFromWinterCGRequest, @@ -74,14 +75,18 @@ export const wrapDenoRequestHandler = ( const dataCollection = client.getDataCollectionOptions(); if (dataCollection.userInfo) { - assignIfSet( - attributes, - 'client.address', - (info?.remoteAddr as Deno.NetAddr)?.hostname ?? (info?.remoteAddr as Deno.UnixAddr)?.path, - ); - assignIfSet(attributes, 'client.port', (info?.remoteAddr as Deno.NetAddr)?.port); + // `client.address` is the originating client, so a forwarding header wins over the socket, which + // behind a proxy holds the proxy's address. + const forwardedFor = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim(); + const socketAddress = (info?.remoteAddr as Deno.NetAddr)?.hostname ?? (info?.remoteAddr as Deno.UnixAddr)?.path; + const clientPort = (info?.remoteAddr as Deno.NetAddr)?.port; + assignIfSet(attributes, CLIENT_ADDRESS, forwardedFor || socketAddress); + assignIfSet(attributes, CLIENT_PORT, clientPort); } + // describes the OSI application-layer protocol (http), not the scheme (might be https) + attributes[NETWORK_PROTOCOL_NAME] = 'http'; + Object.assign(attributes, httpHeadersToSpanAttributes(winterCGHeadersToDict(request.headers), dataCollection)); attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server'; isolationScope.setSDKProcessingMetadata({ diff --git a/packages/deno/test/deno-http.test.ts b/packages/deno/test/deno-http.test.ts index 0944304ac980..9dc0aa4a4362 100644 --- a/packages/deno/test/deno-http.test.ts +++ b/packages/deno/test/deno-http.test.ts @@ -108,6 +108,8 @@ Deno.test({ assertEquals(txn.transaction, 'QUERY /users/42'); assertEquals(txn.contexts?.trace?.data?.['http.method'], 'QUERY'); assertEquals(txn.contexts?.trace?.data?.['http.response.status_code'], 200); + assertEquals(txn.contexts?.trace?.data?.['network.protocol.name'], 'http'); + assertEquals(txn.contexts?.trace?.data?.['network.protocol.version'], '1.1'); }, }); diff --git a/packages/node/src/integrations/http/httpServerSpansIntegration.ts b/packages/node/src/integrations/http/httpServerSpansIntegration.ts index dad376ce65d9..1234321e7433 100644 --- a/packages/node/src/integrations/http/httpServerSpansIntegration.ts +++ b/packages/node/src/integrations/http/httpServerSpansIntegration.ts @@ -11,12 +11,17 @@ import { HTTP_STATUS_CODE, HTTP_TARGET, HTTP_USER_AGENT, - NET_HOST_IP, - NET_HOST_NAME, - NET_HOST_PORT, - NET_PEER_IP, - NET_PEER_PORT, - NET_TRANSPORT, + CLIENT_ADDRESS, + CLIENT_PORT, + NETWORK_LOCAL_ADDRESS, + NETWORK_LOCAL_PORT, + NETWORK_PEER_ADDRESS, + NETWORK_PEER_PORT, + NETWORK_PROTOCOL_NAME, + NETWORK_PROTOCOL_VERSION, + NETWORK_TRANSPORT, + SERVER_ADDRESS, + SERVER_PORT, SENTRY_HTTP_PREFETCH, URL_FRAGMENT, URL_FULL, @@ -175,12 +180,14 @@ const _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions client, ), [HTTP_HOST]: host, - [NET_HOST_NAME]: hostname, - [HTTP_CLIENT_IP]: typeof ips === 'string' ? ips.split(',')[0] : undefined, + [SERVER_ADDRESS]: hostname, + [NETWORK_PROTOCOL_NAME]: 'http', + [NETWORK_PROTOCOL_VERSION]: httpVersion, + [HTTP_CLIENT_IP]: client.getDataCollectionOptions().userInfo ? getForwardedClientAddress(ips) : undefined, [HTTP_USER_AGENT]: userAgent, [HTTP_SCHEME]: scheme, [HTTP_FLAVOR]: httpVersion, - [NET_TRANSPORT]: httpVersion?.toUpperCase() === 'QUIC' ? 'ip_udp' : 'ip_tcp', + [NETWORK_TRANSPORT]: httpVersion?.toUpperCase() === 'QUIC' ? 'udp' : 'tcp', /* eslint-enable typescript/no-deprecated */ ...getRequestContentLengthAttribute(request), ...httpHeadersToSpanAttributes(normalizedRequest.headers || {}, client.getDataCollectionOptions()), @@ -203,7 +210,11 @@ const _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions isEnded = true; - const newAttributes = getIncomingRequestAttributesOnResponse(request, response); + const newAttributes = getIncomingRequestAttributesOnResponse( + request, + response, + client.getDataCollectionOptions().userInfo, + ); span.setAttributes(newAttributes); span.setStatus(status); span.end(); @@ -376,9 +387,18 @@ function isCompressed(headers: IncomingHttpHeaders): boolean { return !!encoding && encoding !== 'identity'; } +/** + * First entry of `X-Forwarded-For`: the client as seen by the outermost proxy. + * https://opentelemetry.io/docs/specs/semconv/registry/attributes/client/#client-address + */ +function getForwardedClientAddress(forwardedFor: string | string[] | undefined): string | undefined { + return typeof forwardedFor === 'string' ? forwardedFor.split(',')[0]?.trim() || undefined : undefined; +} + function getIncomingRequestAttributesOnResponse( request: HttpIncomingMessage, response: HttpServerResponse, + collectClientAddress: boolean, ): SpanAttributes { // take socket from the request, // since it may be detached from the response object in keep-alive mode @@ -392,16 +412,21 @@ function getIncomingRequestAttributesOnResponse( 'http.status_text': statusMessage?.toUpperCase(), }; + if (collectClientAddress) { + // `client.address` is the originating client, so a forwarding header wins over the socket, which + // behind a proxy holds the proxy's address. `network.peer.address` below keeps the socket value. + newAttributes[CLIENT_ADDRESS] = + getForwardedClientAddress(request.headers['x-forwarded-for']) ?? socket?.remoteAddress; + } + if (socket) { const { localAddress, localPort, remoteAddress, remotePort } = socket; - // eslint-disable-next-line typescript/no-deprecated - newAttributes[NET_HOST_IP] = localAddress; - // eslint-disable-next-line typescript/no-deprecated - newAttributes[NET_HOST_PORT] = localPort; - // eslint-disable-next-line typescript/no-deprecated - newAttributes[NET_PEER_IP] = remoteAddress; - // oxlint-disable-next-line typescript/no-deprecated - newAttributes[NET_PEER_PORT] = remotePort; + newAttributes[SERVER_PORT] = localPort; + newAttributes[NETWORK_LOCAL_ADDRESS] = localAddress; + newAttributes[NETWORK_LOCAL_PORT] = localPort; + newAttributes[CLIENT_PORT] = remotePort; + newAttributes[NETWORK_PEER_ADDRESS] = collectClientAddress ? remoteAddress : undefined; + newAttributes[NETWORK_PEER_PORT] = remotePort; } return newAttributes; diff --git a/packages/server-utils/src/integrations/mysql.ts b/packages/server-utils/src/integrations/mysql.ts index fc2d4ff69dd1..69ced51b5dac 100644 --- a/packages/server-utils/src/integrations/mysql.ts +++ b/packages/server-utils/src/integrations/mysql.ts @@ -91,8 +91,8 @@ function instrumentMysql(): void { ...(database ? { [DB_NAMESPACE]: database } : {}), ...(user ? { [DB_USER]: user } : {}), ...(sql ? { [DB_QUERY_TEXT]: sql } : {}), - ...(host ? { [SERVER_ADDRESS]: host } : {}), - ...(portIsNumber ? { [SERVER_PORT]: portNumber } : {}), + [SERVER_ADDRESS]: host, + [SERVER_PORT]: portIsNumber ? portNumber : undefined, }, }); },