diff --git a/packages/opentelemetry-node/test/fixtures/use-http-server.js b/packages/opentelemetry-node/test/fixtures/use-http-server.js new file mode 100644 index 00000000..6acf87df --- /dev/null +++ b/packages/opentelemetry-node/test/fixtures/use-http-server.js @@ -0,0 +1,95 @@ +// Usage: node -r ../../start.js use-http-server.js +// +// This starts a simple echo server, makes two requests to it, then stops the +// server. + +const http = require('http'); + +const server = http.createServer(function onRequest(req, res) { + console.log('incoming request: %s %s %s', req.method, req.url, req.headers); + if (req.url !== '/echo') { + req.resume(); + res.writeHead(404); + res.end(); + return; + } + if (req.method !== 'POST') { + req.resume(); + res.writeHead(405, { + Allow: 'POST', + }); + res.end(); + return; + } + + const chunks = []; + req.on('data', (chunk) => { + chunks.push(chunk); + }); + req.on('end', function () { + const body = Buffer.concat(chunks); + res.writeHead(200, { + 'content-type': 'application/octet-stream', + 'content-length': Buffer.byteLength(body), + }); + res.end(body); + }); +}); + +server.listen(0, '127.0.0.1', async function () { + const port = server.address().port; + + // First request to show a client error. + await new Promise((resolve) => { + const clientReq = http.request( + `http://127.0.0.1:${port}/`, + function (cres) { + console.log( + 'client response: %s %s', + cres.statusCode, + cres.headers + ); + const chunks = []; + cres.on('data', function (chunk) { + chunks.push(chunk); + }); + cres.on('end', function () { + const body = chunks.join(''); + console.log('client response body: %j', body); + resolve(); + }); + } + ); + clientReq.end(); + }); + + // First request to show a client error. + await new Promise((resolve) => { + const clientReq = http.request( + `http://127.0.0.1:${port}/echo`, + { + method: 'POST', + }, + function (cres) { + console.log( + 'client response: %s %s', + cres.statusCode, + cres.headers + ); + const chunks = []; + cres.on('data', function (chunk) { + chunks.push(chunk); + }); + cres.on('end', function () { + const body = chunks.join(''); + console.log('client response body: %j', body); + resolve(); + }); + } + ); + clientReq.write('hi'); + clientReq.end(); + }); + + server.close(); +}); diff --git a/packages/opentelemetry-node/test/fixtures/use-https-get.js b/packages/opentelemetry-node/test/fixtures/use-https-get.js new file mode 100644 index 00000000..e065e0e9 --- /dev/null +++ b/packages/opentelemetry-node/test/fixtures/use-https-get.js @@ -0,0 +1,9 @@ +// Usage: node -r ../../start.js use-https-get.js +const https = require('https'); +https.get('https://www.google.com/', (res) => { + console.log('client response: %s %s', res.statusCode, res.headers); + res.resume(); + res.on('end', () => { + console.log('client response: end'); + }); +}); diff --git a/packages/opentelemetry-node/test/instr-http.test.js b/packages/opentelemetry-node/test/instr-http.test.js index bf00fa10..300b9e76 100644 --- a/packages/opentelemetry-node/test/instr-http.test.js +++ b/packages/opentelemetry-node/test/instr-http.test.js @@ -20,6 +20,66 @@ const testFixtures = [ t.equal(span.scope.name, '@opentelemetry/instrumentation-http'); t.equal(span.name, 'GET'); t.equal(span.kind, 'SPAN_KIND_CLIENT'); + t.equal(span.attributes['http.url'], 'http://www.google.com/'); + }, + }, + { + name: 'https.get', + args: ['./fixtures/use-https-get.js'], + cwd: __dirname, + env: { + NODE_OPTIONS: '--require=../start.js', + }, + // verbose: true, + checkTelemetry: (t, col) => { + const spans = col.sortedSpans; + t.equal(spans.length, 1); + const span = spans[0]; + t.equal(span.scope.name, '@opentelemetry/instrumentation-http'); + t.equal(span.name, 'GET'); + t.equal(span.kind, 'SPAN_KIND_CLIENT'); + t.equal(span.attributes['http.url'], 'https://www.google.com/'); + }, + }, + { + name: 'http.createServer', + args: ['./fixtures/use-http-server.js'], + cwd: __dirname, + env: { + NODE_OPTIONS: '--require=../start.js', + }, + // verbose: true, + checkTelemetry: (t, col) => { + // Expect two traces like this: + // ------ trace 1e45c8 (2 spans) ------ + // span 1d3de9 "GET" (20.1ms, STATUS_CODE_ERROR, SPAN_KIND_CLIENT, GET http://127.0.0.1:64972/ -> 404) + // +14ms `- span ec9d81 "GET" (3.4ms, SPAN_KIND_SERVER, GET http://127.0.0.1:64972/ -> 404) + // ------ trace b8467d (2 spans) ------ + // span bc8a2c "POST" (3.8ms, SPAN_KIND_CLIENT, POST http://127.0.0.1:64972/echo -> 200) + // +2ms `- span 4e7adf "POST" (1.1ms, SPAN_KIND_SERVER, POST http://127.0.0.1:64972/echo -> 200) + const spans = col.sortedSpans; + t.equal(spans.length, 4); + t.equal(spans[0].scope.name, '@opentelemetry/instrumentation-http'); + t.equal(spans[0].name, 'GET'); + t.equal(spans[0].kind, 'SPAN_KIND_CLIENT'); + t.equal(spans[0].status.code, 'STATUS_CODE_ERROR'); + t.equal(spans[0].attributes['http.status_code'], 404); + + t.equal(spans[1].traceId, spans[0].traceId); + t.equal(spans[1].parentSpanId, spans[0].spanId); + t.equal(spans[1].name, 'GET'); + t.equal(spans[1].kind, 'SPAN_KIND_SERVER'); + t.equal(spans[1].attributes['http.status_code'], 404); + + t.equal(spans[2].name, 'POST'); + t.equal(spans[2].kind, 'SPAN_KIND_CLIENT'); + t.equal(spans[2].attributes['http.status_code'], 200); + + t.equal(spans[3].traceId, spans[2].traceId); + t.equal(spans[3].parentSpanId, spans[2].spanId); + t.equal(spans[3].name, 'POST'); + t.equal(spans[3].kind, 'SPAN_KIND_SERVER'); + t.equal(spans[3].attributes['http.status_code'], 200); }, }, ]; diff --git a/packages/opentelemetry-node/test/testutils.js b/packages/opentelemetry-node/test/testutils.js index 6b1d9a70..0734dfa4 100644 --- a/packages/opentelemetry-node/test/testutils.js +++ b/packages/opentelemetry-node/test/testutils.js @@ -238,6 +238,7 @@ function quoteEnv(env) { * * TODO: these types don't represent to added 'resource' and 'scope' properties. * TODO: This LogRecord doesn't include `traceId` et al, because there are 3 LogRecord classes: protos, api-logs, sdk-logs. + * TODO: Likewise for this Span type. * * @typedef {Object} CollectorStore * @property {import('@opentelemetry/api').Span[]} sortedSpans