diff --git a/examples/network/client.js b/examples/network/client.js new file mode 100644 index 0000000000..e7d26f5417 --- /dev/null +++ b/examples/network/client.js @@ -0,0 +1,51 @@ +'use strict'; + +const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api'); +const { NodeTracerProvider } = require('@opentelemetry/node'); +const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http'); +const { NetInstrumentation } = require('@opentelemetry/instrumentation-net'); +const { DnsInstrumentation } = require('@opentelemetry/instrumentation-dns'); +const { registerInstrumentations } = require('@opentelemetry/instrumentation'); +const { SimpleSpanProcessor, ConsoleSpanExporter } = require('@opentelemetry/tracing'); +const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); + +const provider = new NodeTracerProvider(); + +provider.addSpanProcessor(new SimpleSpanProcessor(new JaegerExporter({ + serviceName: 'http-client', +}))); + +provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); + +provider.register(); + +diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); + +registerInstrumentations({ + instrumentations: [ + new NetInstrumentation(), + new HttpInstrumentation(), + new DnsInstrumentation({ + // Avoid dns lookup loop with http zipkin calls + ignoreHostnames: ['localhost'], + }), + ], + tracerProvider: provider, +}); + +require('net'); +require('dns'); +const https = require('https'); +const http = require('http'); + +http.get('http://opentelemetry.io/', () => {}).on('error', (e) => { + console.error(e); +}); + +https.get('https://opentelemetry.io/', () => {}).on('error', (e) => { + console.error(e); +}); + +https.get('https://opentelemetry.io/', { ca: [] }, () => {}).on('error', (e) => { + console.error(e); +}); diff --git a/examples/network/package.json b/examples/network/package.json new file mode 100644 index 0000000000..07015b3618 --- /dev/null +++ b/examples/network/package.json @@ -0,0 +1,44 @@ +{ + "name": "tls-example", + "private": true, + "version": "0.15.0", + "description": "Example of NET & TLS integration with OpenTelemetry", + "main": "index.js", + "scripts": { + "zipkin:client": "cross-env EXPORTER=zipkin node ./client.js", + "jaeger:client": "cross-env EXPORTER=jaeger node ./client.js" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/open-telemetry/opentelemetry-js-contrib.git" + }, + "keywords": [ + "opentelemetry", + "net", + "tls", + "tracing" + ], + "engines": { + "node": ">=8.5.0" + }, + "author": "OpenTelemetry Authors", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/open-telemetry/opentelemetry-js-contrib/issues" + }, + "dependencies": { + "@opentelemetry/api": "^0.18.1", + "@opentelemetry/exporter-jaeger": "^0.18.2", + "@opentelemetry/exporter-zipkin": "^0.18.2", + "@opentelemetry/instrumentation": "^0.18.2", + "@opentelemetry/instrumentation-net": "file:../../plugins/node/opentelemetry-instrumentation-net", + "@opentelemetry/instrumentation-http": "^0.19.0", + "@opentelemetry/instrumentation-dns": "^0.15.0", + "@opentelemetry/node": "^0.18.2", + "@opentelemetry/tracing": "^0.18.2" + }, + "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib#readme", + "devDependencies": { + "cross-env": "^6.0.3" + } +} diff --git a/examples/restify/package.json b/examples/restify/package.json index 7bb3e2b1da..fe4ef15489 100644 --- a/examples/restify/package.json +++ b/examples/restify/package.json @@ -33,6 +33,7 @@ "@opentelemetry/exporter-zipkin": "^0.19.0", "@opentelemetry/instrumentation": "^0.19.0", "@opentelemetry/instrumentation-http": "^0.19.0", + "@opentelemetry/instrumentation-restify": "^0.16.0", "@opentelemetry/node": "^0.19.0", "@opentelemetry/tracing": "^0.19.0", "restify": "^4.3.4" diff --git a/metapackages/auto-instrumentations-node/package.json b/metapackages/auto-instrumentations-node/package.json index 2631db7e34..d83a79cdf8 100644 --- a/metapackages/auto-instrumentations-node/package.json +++ b/metapackages/auto-instrumentations-node/package.json @@ -37,8 +37,6 @@ "rimraf": "3.0.2", "sinon": "10.0.0", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/packages/opentelemetry-test-utils/package.json b/packages/opentelemetry-test-utils/package.json index 00d2281f64..d69127b086 100644 --- a/packages/opentelemetry-test-utils/package.json +++ b/packages/opentelemetry-test-utils/package.json @@ -26,8 +26,6 @@ "devDependencies": { "@types/node": "14.14.43", "gts": "3.1.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json b/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json index bf9932db6d..ef41aae7e8 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json +++ b/plugins/node/opentelemetry-instrumentation-aws-lambda/package.json @@ -50,8 +50,6 @@ "nyc": "15.1.0", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-bunyan/package.json b/plugins/node/opentelemetry-instrumentation-bunyan/package.json index ce8fb923ff..839cfc40c9 100644 --- a/plugins/node/opentelemetry-instrumentation-bunyan/package.json +++ b/plugins/node/opentelemetry-instrumentation-bunyan/package.json @@ -56,8 +56,6 @@ "rimraf": "3.0.2", "sinon": "9.2.4", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-dns/package.json b/plugins/node/opentelemetry-instrumentation-dns/package.json index 30a1ff0317..da790723ab 100644 --- a/plugins/node/opentelemetry-instrumentation-dns/package.json +++ b/plugins/node/opentelemetry-instrumentation-dns/package.json @@ -56,8 +56,6 @@ "rimraf": "3.0.2", "sinon": "10.0.0", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-express/README.md b/plugins/node/opentelemetry-instrumentation-express/README.md index ae2d75749b..2a9404d9ad 100644 --- a/plugins/node/opentelemetry-instrumentation-express/README.md +++ b/plugins/node/opentelemetry-instrumentation-express/README.md @@ -12,7 +12,7 @@ For automatic instrumentation see the ## Installation -This instrumentation relies on HTTP calls to also be instrumented. Make sure you install and enable both. +This instrumentation relies on HTTP calls to also be instrumented. Make sure you install and enable both, otherwise you will not see any spans being exported from the instrumentation. ```bash npm install --save @opentelemetry/instrumentation-http @opentelemetry/instrumentation-express diff --git a/plugins/node/opentelemetry-instrumentation-express/package.json b/plugins/node/opentelemetry-instrumentation-express/package.json index 78bd91f69b..0dbef8ab34 100644 --- a/plugins/node/opentelemetry-instrumentation-express/package.json +++ b/plugins/node/opentelemetry-instrumentation-express/package.json @@ -54,8 +54,6 @@ "nyc": "15.1.0", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-hapi/package.json b/plugins/node/opentelemetry-instrumentation-hapi/package.json index 7c79d8b802..1ee63dad8b 100644 --- a/plugins/node/opentelemetry-instrumentation-hapi/package.json +++ b/plugins/node/opentelemetry-instrumentation-hapi/package.json @@ -54,8 +54,6 @@ "rimraf": "3.0.2", "semver": "7.3.5", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-ioredis/package.json b/plugins/node/opentelemetry-instrumentation-ioredis/package.json index d7227202b4..7e33ca6563 100644 --- a/plugins/node/opentelemetry-instrumentation-ioredis/package.json +++ b/plugins/node/opentelemetry-instrumentation-ioredis/package.json @@ -58,8 +58,6 @@ "nyc": "15.1.0", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-koa/package.json b/plugins/node/opentelemetry-instrumentation-koa/package.json index c957cbbbb3..1e2c3d6c39 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/package.json +++ b/plugins/node/opentelemetry-instrumentation-koa/package.json @@ -56,8 +56,6 @@ "nyc": "15.1.0", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-mongodb/package.json b/plugins/node/opentelemetry-instrumentation-mongodb/package.json index e4c84861e8..bdaf3a3032 100644 --- a/plugins/node/opentelemetry-instrumentation-mongodb/package.json +++ b/plugins/node/opentelemetry-instrumentation-mongodb/package.json @@ -55,8 +55,6 @@ "nyc": "15.1.0", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-mysql/package.json b/plugins/node/opentelemetry-instrumentation-mysql/package.json index 6c720ff5e0..9382004aca 100644 --- a/plugins/node/opentelemetry-instrumentation-mysql/package.json +++ b/plugins/node/opentelemetry-instrumentation-mysql/package.json @@ -53,8 +53,6 @@ "nyc": "15.1.0", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-net/package.json b/plugins/node/opentelemetry-instrumentation-net/package.json index b6e9c30ea3..19848a245e 100644 --- a/plugins/node/opentelemetry-instrumentation-net/package.json +++ b/plugins/node/opentelemetry-instrumentation-net/package.json @@ -54,8 +54,6 @@ "rimraf": "3.0.2", "sinon": "10.0.0", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-net/src/net.ts b/plugins/node/opentelemetry-instrumentation-net/src/net.ts index 7665a62ffe..9a71741296 100644 --- a/plugins/node/opentelemetry-instrumentation-net/src/net.ts +++ b/plugins/node/opentelemetry-instrumentation-net/src/net.ts @@ -26,10 +26,11 @@ import { SemanticAttributes, NetTransportValues, } from '@opentelemetry/semantic-conventions'; -import { Net, NormalizedOptions, SocketEvent } from './types'; +import { Net, NormalizedOptions, SocketEvent, TLSAttributes } from './types'; import { getNormalizedArgs, IPC_TRANSPORT } from './utils'; import { VERSION } from './version'; import { Socket } from 'net'; +import { TLSSocket } from 'tls'; export class NetInstrumentation extends InstrumentationBase { constructor(protected _config: InstrumentationConfig = {}) { @@ -69,11 +70,10 @@ export class NetInstrumentation extends InstrumentationBase { return function patchedConnect(this: Socket, ...args: unknown[]) { const options = getNormalizedArgs(args); - const span = options - ? options.path - ? plugin._startIpcSpan(options, this) - : plugin._startTcpSpan(options, this) - : plugin._startGenericSpan(this); + const span = + this instanceof TLSSocket + ? plugin._startTLSSpan(options, this) + : plugin._startSpan(options, this); return safeExecuteInTheMiddle( () => original.apply(this, args), @@ -92,6 +92,77 @@ export class NetInstrumentation extends InstrumentationBase { }; } + private _startSpan( + options: NormalizedOptions | undefined | null, + socket: Socket + ) { + if (!options) { + return this._startGenericSpan(socket); + } + if (options.path) { + return this._startIpcSpan(options, socket); + } + return this._startTcpSpan(options, socket); + } + + private _startTLSSpan( + options: NormalizedOptions | undefined | null, + socket: TLSSocket + ) { + const tlsSpan = this.tracer.startSpan('tls.connect'); + + const netSpan = this._startSpan(options, socket); + + const otelTlsSpanListener = () => { + const peerCertificate = socket.getPeerCertificate(true); + const cipher = socket.getCipher(); + const protocol = socket.getProtocol(); + const attributes = { + [TLSAttributes.PROTOCOL]: String(protocol), + [TLSAttributes.AUTHORIZED]: String(socket.authorized), + [TLSAttributes.CIPHER_NAME]: cipher.name, + [TLSAttributes.CIPHER_VERSION]: cipher.version, + [TLSAttributes.CERTIFICATE_FINGERPRINT]: peerCertificate.fingerprint, + [TLSAttributes.CERTIFICATE_SERIAL_NUMBER]: peerCertificate.serialNumber, + [TLSAttributes.CERTIFICATE_VALID_FROM]: peerCertificate.valid_from, + [TLSAttributes.CERTIFICATE_VALID_TO]: peerCertificate.valid_to, + [TLSAttributes.ALPN_PROTOCOL]: '', + }; + if (socket.alpnProtocol) { + attributes[TLSAttributes.ALPN_PROTOCOL] = socket.alpnProtocol; + } + + tlsSpan.setAttributes(attributes); + tlsSpan.end(); + }; + + const otelTlsErrorListener = (e: Error) => { + tlsSpan.setStatus({ + code: SpanStatusCode.ERROR, + message: e.message, + }); + tlsSpan.end(); + }; + + /* if we use once and tls.connect() uses a callback this is never executed */ + socket.prependOnceListener(SocketEvent.SECURE_CONNECT, otelTlsSpanListener); + socket.once(SocketEvent.ERROR, otelTlsErrorListener); + + const otelTlsRemoveListeners = () => { + socket.removeListener(SocketEvent.SECURE_CONNECT, otelTlsSpanListener); + socket.removeListener(SocketEvent.ERROR, otelTlsErrorListener); + for (const event of SOCKET_EVENTS) { + socket.removeListener(event, otelTlsRemoveListeners); + } + }; + + for (const event of [SocketEvent.CLOSE, SocketEvent.ERROR]) { + socket.once(event, otelTlsRemoveListeners); + } + + return netSpan; + } + /* It might still be useful to pick up errors due to invalid connect arguments. */ private _startGenericSpan(socket: Socket) { const span = this.tracer.startSpan('connect'); diff --git a/plugins/node/opentelemetry-instrumentation-net/src/types.ts b/plugins/node/opentelemetry-instrumentation-net/src/types.ts index f767252dcf..5db05c71cc 100644 --- a/plugins/node/opentelemetry-instrumentation-net/src/types.ts +++ b/plugins/node/opentelemetry-instrumentation-net/src/types.ts @@ -28,4 +28,18 @@ export enum SocketEvent { CLOSE = 'close', CONNECT = 'connect', ERROR = 'error', + SECURE_CONNECT = 'secureConnect', +} + +/* The following attributes are not offical, see open-telemetry/opentelemetry-specification#1652 */ +export enum TLSAttributes { + PROTOCOL = 'tls.protocol', + AUTHORIZED = 'tls.authorized', + CIPHER_NAME = 'tls.cipher.name', + CIPHER_VERSION = 'tls.cipher.version', + CERTIFICATE_FINGERPRINT = 'tls.certificate.fingerprint', + CERTIFICATE_SERIAL_NUMBER = 'tls.certificate.serialNumber', + CERTIFICATE_VALID_FROM = 'tls.certificate.validFrom', + CERTIFICATE_VALID_TO = 'tls.certificate.validTo', + ALPN_PROTOCOL = 'tls.alpnProtocol', } diff --git a/plugins/node/opentelemetry-instrumentation-net/test/tls.test.ts b/plugins/node/opentelemetry-instrumentation-net/test/tls.test.ts new file mode 100644 index 0000000000..d89a00aa4e --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-net/test/tls.test.ts @@ -0,0 +1,172 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SpanStatusCode } from '@opentelemetry/api'; +import { + InMemorySpanExporter, + SimpleSpanProcessor, +} from '@opentelemetry/tracing'; +import { NodeTracerProvider } from '@opentelemetry/node'; +import * as assert from 'assert'; +import * as tls from 'tls'; +import { NetInstrumentation } from '../src/net'; +import { SocketEvent } from '../src/types'; +import { + assertTLSSpan, + HOST, + TLS_SERVER_CERT, + TLS_SERVER_KEY, + PORT, +} from './utils'; + +const memoryExporter = new InMemorySpanExporter(); +const provider = new NodeTracerProvider(); +provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); + +function getTLSSpans() { + const spans = memoryExporter.getFinishedSpans(); + assert.strictEqual(spans.length, 2); + const [netSpan, tlsSpan] = spans; + return { + netSpan, + tlsSpan, + }; +} + +describe('NetInstrumentation', () => { + let instrumentation: NetInstrumentation; + let tlsServer: tls.Server; + let tlsSocket: tls.TLSSocket; + + before(() => { + instrumentation = new NetInstrumentation(); + instrumentation.setTracerProvider(provider); + require('net'); + }); + + before(done => { + tlsServer = tls.createServer({ + cert: TLS_SERVER_CERT, + key: TLS_SERVER_KEY, + // Make sure tests run on nodejs v8 and v10 the same as on v12+ + maxVersion: 'TLSv1.2', + }); + tlsServer.listen(PORT, done); + }); + + afterEach(() => { + memoryExporter.reset(); + tlsSocket.destroy(); + }); + + after(() => { + instrumentation.disable(); + tlsServer.close(); + }); + + describe('successful tls.connect produces a span', () => { + it('should produce a span with "onSecure" callback', done => { + tlsSocket = tls.connect( + PORT, + HOST, + { + ca: [TLS_SERVER_CERT], + checkServerIdentity: () => { + return undefined; + }, + }, + () => { + assertTLSSpan(getTLSSpans(), tlsSocket); + done(); + } + ); + }); + + it('should produce a span without "onSecure" callback', done => { + tlsSocket = tls.connect(PORT, HOST, { + ca: [TLS_SERVER_CERT], + checkServerIdentity: () => { + return undefined; + }, + }); + tlsServer.once('secureConnection', c => { + c.end(); + }); + tlsSocket.once('end', () => { + assertTLSSpan(getTLSSpans(), tlsSocket); + done(); + }); + }); + + it('should produce an error span when certificate is not trusted', done => { + tlsSocket = tls.connect( + PORT, + HOST, + { + ca: [], + checkServerIdentity: () => { + return undefined; + }, + }, + () => { + assertTLSSpan(getTLSSpans(), tlsSocket); + done(); + } + ); + tlsSocket.on('error', error => { + const { tlsSpan } = getTLSSpans(); + assert.strictEqual(tlsSpan.status.message, 'self signed certificate'); + assert.strictEqual(tlsSpan.status.code, SpanStatusCode.ERROR); + done(); + }); + }); + }); + + describe('cleanup', () => { + function assertNoDanglingListeners(tlsSocket: tls.TLSSocket) { + const events = new Set(tlsSocket.eventNames()); + + for (const event of [ + SocketEvent.CONNECT, + SocketEvent.SECURE_CONNECT, + SocketEvent.ERROR, + ]) { + assert.equal(events.has(event), false); + } + assert.strictEqual(tlsSocket.listenerCount(SocketEvent.CLOSE), 1); + } + + it('should clean up listeners for tls.connect', done => { + tlsSocket = tls.connect( + PORT, + HOST, + { + ca: [TLS_SERVER_CERT], + checkServerIdentity: () => { + return undefined; + }, + }, + () => { + tlsSocket.destroy(); + tlsSocket.once(SocketEvent.CLOSE, () => { + assertNoDanglingListeners(tlsSocket); + done(); + }); + } + ); + }); + }); +}); diff --git a/plugins/node/opentelemetry-instrumentation-net/test/utils.ts b/plugins/node/opentelemetry-instrumentation-net/test/utils.ts index 5f4f6d3138..4a9316e4a2 100644 --- a/plugins/node/opentelemetry-instrumentation-net/test/utils.ts +++ b/plugins/node/opentelemetry-instrumentation-net/test/utils.ts @@ -25,6 +25,7 @@ import * as path from 'path'; import * as os from 'os'; import { Socket } from 'net'; import { IPC_TRANSPORT } from '../src/utils'; +import { TLSAttributes } from '../src/types'; export const PORT = 42123; export const HOST = 'localhost'; @@ -52,6 +53,52 @@ export function assertIpcSpan(span: ReadableSpan) { assertAttrib(span, SemanticAttributes.NET_PEER_NAME, IPC_PATH); } +export function assertTLSSpan( + { netSpan, tlsSpan }: { netSpan: ReadableSpan; tlsSpan: ReadableSpan }, + socket: Socket +) { + assertSpanKind(netSpan); + assertAttrib( + netSpan, + SemanticAttributes.NET_TRANSPORT, + NetTransportValues.IP_TCP + ); + assertAttrib(netSpan, SemanticAttributes.NET_PEER_NAME, HOST); + assertAttrib(netSpan, SemanticAttributes.NET_PEER_PORT, PORT); + // Node.JS 10 sets socket.localAddress & socket.localPort to "undefined" when a connection is + // ended, so one of the tests fails, so we skip them for TLS + // assertAttrib(span, SemanticAttributes.NET_HOST_IP, socket.localAddress); + //assertAttrib(netSpan, SemanticAttributes.NET_HOST_PORT, socket.localPort); + + assertAttrib(tlsSpan, TLSAttributes.PROTOCOL, 'TLSv1.2'); + assertAttrib(tlsSpan, TLSAttributes.AUTHORIZED, 'true'); + assertAttrib( + tlsSpan, + TLSAttributes.CIPHER_NAME, + 'ECDHE-RSA-AES128-GCM-SHA256' + ); + assertAttrib( + tlsSpan, + TLSAttributes.CERTIFICATE_FINGERPRINT, + '60:58:0C:4B:52:20:2A:53:4F:50:93:3A:2F:F7:72:06:DD:B3:30:DC' + ); + assertAttrib( + tlsSpan, + TLSAttributes.CERTIFICATE_SERIAL_NUMBER, + 'D789EA9C1A7887D5' + ); + assertAttrib( + tlsSpan, + TLSAttributes.CERTIFICATE_VALID_FROM, + 'Apr 22 12:27:31 2021 GMT' + ); + assertAttrib( + tlsSpan, + TLSAttributes.CERTIFICATE_VALID_TO, + 'May 22 12:27:31 2021 GMT' + ); +} + export function assertSpanKind(span: ReadableSpan) { assert.strictEqual(span.kind, SpanKind.INTERNAL); } @@ -59,3 +106,89 @@ export function assertSpanKind(span: ReadableSpan) { export function assertAttrib(span: ReadableSpan, attrib: string, value: any) { assert.strictEqual(span.attributes[attrib], value); } + +export const TLS_SERVER_CERT = `-----BEGIN CERTIFICATE----- +MIIFrjCCA5YCCQDXieqcGniH1TANBgkqhkiG9w0BAQUFADCBmDELMAkGA1UEBhMC +RVgxEDAOBgNVBAgMB0V4YW1wbGUxFTATBgNVBAcMDEV4YW1wbGUgQ2l0eTEWMBQG +A1UECgwNT3BlblRlbGVtZXRyeTETMBEGA1UECwwKSlMgQ29udHJpYjESMBAGA1UE +AwwJbG9jYWxob3N0MR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4X +DTIxMDQyMjEyMjczMVoXDTIxMDUyMjEyMjczMVowgZgxCzAJBgNVBAYTAkVYMRAw +DgYDVQQIDAdFeGFtcGxlMRUwEwYDVQQHDAxFeGFtcGxlIENpdHkxFjAUBgNVBAoM +DU9wZW5UZWxlbWV0cnkxEzARBgNVBAsMCkpTIENvbnRyaWIxEjAQBgNVBAMMCWxv +Y2FsaG9zdDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO4Kz5+KCwKQg7eojoyzeTzdI52aWN5b +EySHB36+hXatVEBf1a/01CIKxmZPalRJj6PojDyLNGzf6ueVQIJ2B8A7G4I7eDqK +juqhYbaJpUm2Il9RI6QH5IhNMaVabOOppYX5FNHOh6x7MUVQ0JstH/lNr8NzyDpk +fZJGbWzPFmYOstiUz3Zk+G7XJAT+HDBWOWiTdcslsXsl0giYzbZ0V3+ofA0V/Sp3 +UDbFSxAWdQ0fxia1fCGubYheZP6w8rAIz8roc8kDvlvgWowuqltGSLLoCeei/3xe +ZB8LFl37vE38niOMxIcnUS5ddnGgO4jvlOb6iGe31RNBbVU4NhRKOEOKwy+GQfxu +ZRH4nfzdO984OPpj/LHBbgDCMken6KxmPPznZ8K1jmT8PlSC04Kc5z/bb7E5mJyF +ixglq6CLxT2n7pDSILKsK74dE0fhQhnJ3bjT2U3ZISYox1JZmT5krmdpNk7xpICn +0GdobbXObWAqaTqRmMwBZXoV2d9UP/UJUr0OFsZbf4xuW8O+KVdrx4T0ZiQgHyZM +gAxzC0I6yJQlBG7Q3T9FnVkNaUGJmjI2PT9v91VRmER3DzftB3n5jg+yWJU4G76A +6OdZGjQhUIjiP6KmnaaMheHKo+SNRxH4T/ZDIsebn0LLurBQ46Z9DNnoep5iiRC5 +xFK/bqUl0jd9AgMBAAEwDQYJKoZIhvcNAQEFBQADggIBADc0D7rxXeuqUX27K51i +yQ/0COhEFQW4NcjThLiMt8QDRidqfIhZwdx/KXf/6zwycCizZE9FKVXXphcR/9xn +nJ6VlZSYXg4MG/Zkm2LpH0zNL44DXjV/VoHDaQuksXqxQkYoAKY8q8w2lpVRcvEG +726FzsZEPIzU/p0LUkKf4EixaoaFHCSLn2Ee7ArHF4T9nuSEnxFTao99zo8zQdwz +Suye5FLiHtgAK7J17uACB++VzyRPR/9MjOf1JOtZoM5sMW7ivWahvU8YTDyOsYSp +E0K5NlIpZaZI8kfXkDV09UIzaxw2RwObDf6CNzRYWhG1kS/nTyA+5Ni6OjTck/6P +/7OB5TNXiGdWs6mf1NcdwGUPKYQH4w/NYBs5auLpuluGgtcA9tCHKBnQ7IHdhYmh +OYoaBdyH3PhVxxFM+lny+p4ILsr9wNkEBkU0ox+xGbp8MgrO5pKL0pFy0KqQwQxb +V/Y4o5xOXS4WgBeaxkZyDYRUsqytiur45+se4iKmH8q08H0kFEmZlhKVKecquZx9 +MqTXbVIYqzUyx1hD8SnvtiDvDl3K7pb5EN41pfDrvcxlQ526Yrdtkurh4VmlRLr0 +IuxGGP0Nxr1/Sb+WKA7Oi+iBQnoCKyC9InvlNGETmnqdyTeOuvYz/LzCbpB/cKUR +fkjAnQ+Dk8cIznfmjHp6IJw1 +-----END CERTIFICATE-----`; + +export const TLS_SERVER_KEY = `-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY-----`; diff --git a/plugins/node/opentelemetry-instrumentation-pg/package.json b/plugins/node/opentelemetry-instrumentation-pg/package.json index 61e2f83b70..2442b4b92c 100644 --- a/plugins/node/opentelemetry-instrumentation-pg/package.json +++ b/plugins/node/opentelemetry-instrumentation-pg/package.json @@ -4,7 +4,7 @@ "description": "OpenTelemetry postgres automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", - "repository": "open-telemetry/opentelemetry-js", + "repository": "open-telemetry/opentelemetry-js-contrib", "scripts": { "clean": "rimraf build/*", "compile": "npm run version:update && tsc -p .", @@ -62,8 +62,6 @@ "pg-pool": "3.3.0", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-pino/package.json b/plugins/node/opentelemetry-instrumentation-pino/package.json index acdfdbd5ee..9c39e6ca10 100644 --- a/plugins/node/opentelemetry-instrumentation-pino/package.json +++ b/plugins/node/opentelemetry-instrumentation-pino/package.json @@ -58,8 +58,6 @@ "sinon": "9.2.4", "ts-mocha": "8.0.0", "ts-node": "9.1.1", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-redis/package.json b/plugins/node/opentelemetry-instrumentation-redis/package.json index 7dfe3b0126..c44742b169 100644 --- a/plugins/node/opentelemetry-instrumentation-redis/package.json +++ b/plugins/node/opentelemetry-instrumentation-redis/package.json @@ -57,8 +57,6 @@ "redis": "3.1.2", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-restify/package.json b/plugins/node/opentelemetry-instrumentation-restify/package.json index 43a3acce97..85a44efea9 100644 --- a/plugins/node/opentelemetry-instrumentation-restify/package.json +++ b/plugins/node/opentelemetry-instrumentation-restify/package.json @@ -53,8 +53,6 @@ "restify": "4.3.4", "rimraf": "3.0.2", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": { diff --git a/plugins/node/opentelemetry-instrumentation-winston/package.json b/plugins/node/opentelemetry-instrumentation-winston/package.json index d5cf6c34fb..a16e8089bc 100644 --- a/plugins/node/opentelemetry-instrumentation-winston/package.json +++ b/plugins/node/opentelemetry-instrumentation-winston/package.json @@ -55,8 +55,6 @@ "rimraf": "3.0.2", "sinon": "9.2.4", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4", "winston": "3.3.3", "winston2": "npm:winston@2.4.5" diff --git a/plugins/web/opentelemetry-instrumentation-document-load/package.json b/plugins/web/opentelemetry-instrumentation-document-load/package.json index 82d7ef4006..938863374d 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/package.json +++ b/plugins/web/opentelemetry-instrumentation-document-load/package.json @@ -68,8 +68,6 @@ "sinon": "10.0.0", "ts-loader": "8.2.0", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4", "webpack": "4.46.0", "webpack-cli": "4.6.0", diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts index 764f5b6146..14115ccf70 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/documentLoad.ts @@ -115,6 +115,12 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { } }); + rootSpan.setAttribute(SemanticAttributes.HTTP_URL, location.href); + rootSpan.setAttribute( + SemanticAttributes.HTTP_USER_AGENT, + navigator.userAgent + ); + this._addResourcesSpans(rootSpan); addSpanNetworkEvent(rootSpan, PTN.FETCH_START, entries); diff --git a/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts b/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts index 63b0d921b7..1548a96710 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts @@ -174,6 +174,9 @@ const entriesFallback = { loadEventEnd: 1571078170394, } as any; +const userAgent = + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'; + function ensureNetworkEventsExists(events: TimedEvent[]) { assert.strictEqual(events[0].name, PTN.FETCH_START); assert.strictEqual(events[1].name, PTN.DOMAIN_LOOKUP_START); @@ -198,6 +201,7 @@ describe('DocumentLoad Instrumentation', () => { writable: true, value: 'complete', }); + sandbox.replaceGetter(navigator, 'userAgent', () => userAgent); plugin = new DocumentLoadInstrumentation({ enabled: false, }); @@ -492,31 +496,37 @@ describe('DocumentLoad Instrumentation', () => { it('should export correct span with events', done => { plugin.enable(); setTimeout(() => { - const rootSpan = exporter.getFinishedSpans()[0] as ReadableSpan; - const fetchSpan = exporter.getFinishedSpans()[1] as ReadableSpan; - const rsEvents = rootSpan.events; + const fetchSpan = exporter.getFinishedSpans()[0] as ReadableSpan; + const rootSpan = exporter.getFinishedSpans()[1] as ReadableSpan; const fsEvents = fetchSpan.events; + const rsEvents = rootSpan.events; - assert.strictEqual(rootSpan.name, 'documentFetch'); - assert.strictEqual(fetchSpan.name, 'documentLoad'); + assert.strictEqual(fetchSpan.name, 'documentFetch'); + assert.strictEqual(rootSpan.name, 'documentLoad'); - ensureNetworkEventsExists(rsEvents); + assert.strictEqual( + rootSpan.attributes['http.url'], + 'http://localhost:9876/context.html' + ); + assert.strictEqual(rootSpan.attributes['http.user_agent'], userAgent); - assert.strictEqual(fsEvents[0].name, PTN.FETCH_START); - assert.strictEqual(fsEvents[1].name, PTN.UNLOAD_EVENT_START); - assert.strictEqual(fsEvents[2].name, PTN.UNLOAD_EVENT_END); - assert.strictEqual(fsEvents[3].name, PTN.DOM_INTERACTIVE); + ensureNetworkEventsExists(fsEvents); + + assert.strictEqual(rsEvents[0].name, PTN.FETCH_START); + assert.strictEqual(rsEvents[1].name, PTN.UNLOAD_EVENT_START); + assert.strictEqual(rsEvents[2].name, PTN.UNLOAD_EVENT_END); + assert.strictEqual(rsEvents[3].name, PTN.DOM_INTERACTIVE); assert.strictEqual( - fsEvents[4].name, + rsEvents[4].name, PTN.DOM_CONTENT_LOADED_EVENT_START ); - assert.strictEqual(fsEvents[5].name, PTN.DOM_CONTENT_LOADED_EVENT_END); - assert.strictEqual(fsEvents[6].name, PTN.DOM_COMPLETE); - assert.strictEqual(fsEvents[7].name, PTN.LOAD_EVENT_START); - assert.strictEqual(fsEvents[8].name, PTN.LOAD_EVENT_END); + assert.strictEqual(rsEvents[5].name, PTN.DOM_CONTENT_LOADED_EVENT_END); + assert.strictEqual(rsEvents[6].name, PTN.DOM_COMPLETE); + assert.strictEqual(rsEvents[7].name, PTN.LOAD_EVENT_START); + assert.strictEqual(rsEvents[8].name, PTN.LOAD_EVENT_END); - assert.strictEqual(rsEvents.length, 9); assert.strictEqual(fsEvents.length, 9); + assert.strictEqual(rsEvents.length, 9); assert.strictEqual(exporter.getFinishedSpans().length, 2); done(); }); diff --git a/plugins/web/opentelemetry-instrumentation-user-interaction/package.json b/plugins/web/opentelemetry-instrumentation-user-interaction/package.json index 3bdb88a72d..88d6efe061 100644 --- a/plugins/web/opentelemetry-instrumentation-user-interaction/package.json +++ b/plugins/web/opentelemetry-instrumentation-user-interaction/package.json @@ -73,8 +73,6 @@ "sinon": "10.0.0", "ts-loader": "8.2.0", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4", "webpack": "4.46.0", "webpack-cli": "4.6.0", diff --git a/plugins/web/opentelemetry-plugin-react-load/package.json b/plugins/web/opentelemetry-plugin-react-load/package.json index 510fd42f2d..a6a1f4c81b 100644 --- a/plugins/web/opentelemetry-plugin-react-load/package.json +++ b/plugins/web/opentelemetry-plugin-react-load/package.json @@ -75,8 +75,6 @@ "sinon": "10.0.0", "ts-loader": "8.2.0", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4", "webpack": "4.46.0", "webpack-cli": "4.6.0", diff --git a/propagators/opentelemetry-propagator-grpc-census-binary/package.json b/propagators/opentelemetry-propagator-grpc-census-binary/package.json index 9d558740e7..6a36ac00a4 100644 --- a/propagators/opentelemetry-propagator-grpc-census-binary/package.json +++ b/propagators/opentelemetry-propagator-grpc-census-binary/package.json @@ -52,8 +52,6 @@ "rimraf": "3.0.2", "ts-loader": "8.2.0", "ts-mocha": "8.0.0", - "tslint-consistent-codestyle": "1.16.0", - "tslint-microsoft-contrib": "6.2.0", "typescript": "4.2.4" }, "dependencies": {