diff --git a/packages/opentelemetry-host-metrics/README.md b/packages/opentelemetry-host-metrics/README.md index f613fba2a6..46952bd1a3 100644 --- a/packages/opentelemetry-host-metrics/README.md +++ b/packages/opentelemetry-host-metrics/README.md @@ -32,13 +32,47 @@ const exporter = new PrometheusExporter( } ); -const meterProvider = new MeterProvider(); -meterProvider.addMetricReader(exporter); +const meterProvider = new MeterProvider({ + readers: [reader], +}); const hostMetrics = new HostMetrics({ meterProvider, name: 'example-host-metrics' }); hostMetrics.start(); ``` +## Semantic Conventions + +This package uses Semantic Conventions [Version 1.25.0](https://github.com/open-telemetry/semantic-conventions/tree/v1.25.0/docs/system). +As for now the Semantic Conventions are bundled in this package but eventually will be imported from `@opentelemetry/semantic-conventions` package when it is updated to latest version. +Ref: [opentelemetry-js/issues/4235](https://github.com/open-telemetry/opentelemetry-js/issues/4235) + +Metrics collected: + +| Metric | Short Description | +| --------------------------- | --------------------------------------------------------- | +| `system.cpu.time` | Seconds each logical CPU spent on each mode | +| `system.cpu.utilization` | CPU usage time (0-1) | +| `system.memory.usage` | Reports memory in use by state | +| `system.memory.utilization` | Memory usage (0-1) | +| `system.network.dropped` | Count of packets that are dropped | +| `system.network.errors` | Count of network errors detected | +| `system.network.io` | Network flow direction | +| `process.cpu.time` | Total CPU seconds | +| `process.cpu.utilization` | Difference in process.cpu.time since the last measurement | +| `process.memory.usage` | The amount of physical memory in use | + +Attributes collected: + +| Metric | Short Description | +| --------------------------- | ---------------------------------- | +| `system.cpu.logical_number` | The logical CPU number | +| `system.cpu.state` | The state of the CPU | +| `system.memory.state` | The memory state | +| `system.device` | The device identifier | +| `network.io.direction` | The network IO operation direction | +| `system.network.state` | The network state | +| `process.cpu.state` | The CPU state | + ## Useful links - For more information on OpenTelemetry, visit: diff --git a/packages/opentelemetry-host-metrics/src/enum.ts b/packages/opentelemetry-host-metrics/src/enum.ts index acfe4adc05..19e4efbda4 100644 --- a/packages/opentelemetry-host-metrics/src/enum.ts +++ b/packages/opentelemetry-host-metrics/src/enum.ts @@ -32,11 +32,9 @@ export enum ATTRIBUTE_NAMES { SYSTEM_CPU_STATE = 'system.cpu.state', SYSTEM_MEMORY_STATE = 'system.memory.state', SYSTEM_DEVICE = 'system.device', - SYSTEM_NETWORK_DIRECTION = 'system.network.direction', + NETWORK_IO_DIRECTION = 'network.io.direction', SYSTEM_NETWORK_STATE = 'system.network.state', - // TODO: change value if semconv changes - // https://github.com/open-telemetry/opentelemetry-specification/issues/3776 - PROCESS_CPU_STATE = 'state', + PROCESS_CPU_STATE = 'process.cpu.state', } export enum CPU_LABELS { diff --git a/packages/opentelemetry-host-metrics/src/metric.ts b/packages/opentelemetry-host-metrics/src/metric.ts index 2604e95d00..b117ce4307 100644 --- a/packages/opentelemetry-host-metrics/src/metric.ts +++ b/packages/opentelemetry-host-metrics/src/metric.ts @@ -151,7 +151,7 @@ export class HostMetrics extends BaseMetrics { networkUsages: NetworkData[] ): void { const deviceAttr = enums.ATTRIBUTE_NAMES.SYSTEM_DEVICE; - const directionAttr = enums.ATTRIBUTE_NAMES.SYSTEM_NETWORK_DIRECTION; + const directionAttr = enums.ATTRIBUTE_NAMES.NETWORK_IO_DIRECTION; for (let i = 0, j = networkUsages.length; i < j; i++) { const networkUsage = networkUsages[i]; diff --git a/packages/opentelemetry-host-metrics/src/util.ts b/packages/opentelemetry-host-metrics/src/util.ts index e26b0f7610..05a6622c30 100644 --- a/packages/opentelemetry-host-metrics/src/util.ts +++ b/packages/opentelemetry-host-metrics/src/util.ts @@ -14,6 +14,6 @@ * limitations under the License. */ -export function ObjectKeys(t: T) { +export function ObjectKeys>(t: T) { return Object.keys(t) as (keyof T)[]; } diff --git a/packages/opentelemetry-host-metrics/test/metric.test.ts b/packages/opentelemetry-host-metrics/test/metric.test.ts index 196e74e702..ef89a8c53b 100644 --- a/packages/opentelemetry-host-metrics/test/metric.test.ts +++ b/packages/opentelemetry-host-metrics/test/metric.test.ts @@ -141,8 +141,9 @@ describe('Host Metrics', () => { reader = new TestMetricReader(); - meterProvider = new MeterProvider(); - meterProvider.addMetricReader(reader); + meterProvider = new MeterProvider({ + readers: [reader], + }); hostMetrics = new HostMetrics({ meterProvider, @@ -169,7 +170,7 @@ describe('Host Metrics', () => { const sysCpuNumAttr = ATTRIBUTE_NAMES.SYSTEM_CPU_LOGICAL_NUMBER; const sysMemStateAttr = ATTRIBUTE_NAMES.SYSTEM_MEMORY_STATE; const sysDeviceAttr = ATTRIBUTE_NAMES.SYSTEM_DEVICE; - const sysNetDirAttr = ATTRIBUTE_NAMES.SYSTEM_NETWORK_DIRECTION; + const sysNetDirAttr = ATTRIBUTE_NAMES.NETWORK_IO_DIRECTION; const procCpuStateAttr = ATTRIBUTE_NAMES.PROCESS_CPU_STATE; it('should export CPU time metrics', async () => { diff --git a/plugins/node/opentelemetry-instrumentation-pg/README.md b/plugins/node/opentelemetry-instrumentation-pg/README.md index 3f624bd3b3..abc18e2089 100644 --- a/plugins/node/opentelemetry-instrumentation-pg/README.md +++ b/plugins/node/opentelemetry-instrumentation-pg/README.md @@ -38,8 +38,6 @@ registerInstrumentations({ PgInstrumentation contains both pg and [`pg.Pool`](https://node-postgres.com/api/pool) so it will be instrumented automatically. -See [examples/postgres](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/examples/postgres) for a short example. - ### PostgreSQL Instrumentation Options PostgreSQL instrumentation has few options available to choose from. You can set the following: diff --git a/plugins/web/opentelemetry-instrumentation-document-load/README.md b/plugins/web/opentelemetry-instrumentation-document-load/README.md index 3d87e40398..a538ecf399 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/README.md +++ b/plugins/web/opentelemetry-instrumentation-document-load/README.md @@ -111,6 +111,18 @@ registerInstrumentations({ See [examples/tracer-web](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/tracer-web) for a short example. +## Document Load Instrumentation Options + +The document load instrumentation plugin has few options available to choose from. You can set the following: + +| Options | Type | Description | +|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|-----------------------------------------------------------------------------------------| +| `applyCustomAttributesOnSpan.documentLoad`| `DocumentLoadCustomAttributeFunction` | Function for adding custom attributes to `documentLoad` spans. | +| `applyCustomAttributesOnSpan.documentFetch` | `DocumentLoadCustomAttributeFunction` | Function for adding custom attributes to `documentFetch` spans. | +| `applyCustomAttributesOnSpan.resourceFetch` | `ResourceFetchCustomAttributeFunction` | Function for adding custom attributes to `resourceFetch` spans | +| `ignoreNetworkEvents` | `boolean` | Ignore adding [network events as span events](https://github.com/open-telemetry/opentelemetry-js/blob/e49c4c7f42c6c444da3f802687cfa4f2d6983f46/packages/opentelemetry-sdk-trace-web/src/enums/PerformanceTimingNames.ts#L17) for document fetch and resource fetch spans. | +| `ignorePerformancePaintEvents` | `boolean` | Ignore adding performance resource paint span events to document load spans. | + ## Semantic Conventions This package uses `@opentelemetry/semantic-conventions` version `1.22+`, which implements Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md) diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts index cdde8cfefd..5849be561d 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts @@ -120,7 +120,9 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { if (fetchSpan) { fetchSpan.setAttribute(SEMATTRS_HTTP_URL, location.href); context.with(trace.setSpan(context.active(), fetchSpan), () => { - addSpanNetworkEvents(fetchSpan, entries); + if (!this._getConfig().ignoreNetworkEvents) { + addSpanNetworkEvents(fetchSpan, entries); + } this._addCustomAttributesOnSpan( fetchSpan, this._getConfig().applyCustomAttributesOnSpan?.documentFetch @@ -135,21 +137,30 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { this._addResourcesSpans(rootSpan); - addSpanNetworkEvent(rootSpan, PTN.FETCH_START, entries); - addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_START, entries); - addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_END, entries); - addSpanNetworkEvent(rootSpan, PTN.DOM_INTERACTIVE, entries); - addSpanNetworkEvent( - rootSpan, - PTN.DOM_CONTENT_LOADED_EVENT_START, - entries - ); - addSpanNetworkEvent(rootSpan, PTN.DOM_CONTENT_LOADED_EVENT_END, entries); - addSpanNetworkEvent(rootSpan, PTN.DOM_COMPLETE, entries); - addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_START, entries); - addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_END, entries); + if (!this._getConfig().ignoreNetworkEvents) { + addSpanNetworkEvent(rootSpan, PTN.FETCH_START, entries); + addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_START, entries); + addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_END, entries); + addSpanNetworkEvent(rootSpan, PTN.DOM_INTERACTIVE, entries); + addSpanNetworkEvent( + rootSpan, + PTN.DOM_CONTENT_LOADED_EVENT_START, + entries + ); + addSpanNetworkEvent( + rootSpan, + PTN.DOM_CONTENT_LOADED_EVENT_END, + entries + ); + addSpanNetworkEvent(rootSpan, PTN.DOM_COMPLETE, entries); + addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_START, entries); + addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_END, entries); + } + + if (!this._getConfig().ignorePerformancePaintEvents) { + addSpanPerformancePaintEvents(rootSpan); + } - addSpanPerformancePaintEvents(rootSpan); this._addCustomAttributesOnSpan( rootSpan, this._getConfig().applyCustomAttributesOnSpan?.documentLoad @@ -197,7 +208,9 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { ); if (span) { span.setAttribute(SEMATTRS_HTTP_URL, resource.name); - addSpanNetworkEvents(span, resource); + if (!this._getConfig().ignoreNetworkEvents) { + addSpanNetworkEvents(span, resource); + } this._addCustomAttributesOnResourceSpan( span, resource, diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts index a3188c4706..8ff85d48cb 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts @@ -35,4 +35,38 @@ export interface DocumentLoadInstrumentationConfig documentFetch?: DocumentLoadCustomAttributeFunction; resourceFetch?: ResourceFetchCustomAttributeFunction; }; + + /** Ignore adding network events as span events for document fetch and resource fetch spans. + * This instrumentation will send the following span events by default: + * connectEnd + * connectStart + * decodedBodySize + * domComplete + * domContentLoadedEventEnd + * domContentLoadedEventStart + * domInteractive + * domainLookupEnd + * domainLookupStart + * encodedBodySize + * fetchStart + * loadEventEnd + * loadEventStart + * navigationStart + * redirectEnd + * redirectStart + * requestStart + * responseEnd + * responseStart + * secureConnectionStart + * unloadEventEnd + * unloadEventStart + */ + ignoreNetworkEvents?: boolean; + + /** Ignore adding performance paint span events on document load spans + * This instrumentation will send the following span events by default: + * firstContentfulPaint + * firstPaint + */ + ignorePerformancePaintEvents?: boolean; } 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 a0aba71c3e..a239945bec 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts @@ -755,6 +755,76 @@ describe('DocumentLoad Instrumentation', () => { }); }); }); + + describe('ignore span events if specified', () => { + let spyEntries: any; + beforeEach(() => { + spyEntries = sandbox.stub(window.performance, 'getEntriesByType'); + spyEntries.withArgs('navigation').returns([entries]); + spyEntries.withArgs('resource').returns(resources); + spyEntries.withArgs('paint').returns(paintEntries); + }); + + afterEach(() => { + spyEntries.restore(); + }); + + it('should ignore network span events if ignoreNetworkEvents is set to true', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + ignoreNetworkEvents: true, + }); + plugin.enable(); + + setTimeout(() => { + const rootSpan = exporter.getFinishedSpans()[0] as ReadableSpan; + const fetchSpan = exporter.getFinishedSpans()[1] as ReadableSpan; + const loadSpan = exporter.getFinishedSpans()[3] as ReadableSpan; + + const rsEvents = rootSpan.events; + const fsEvents = fetchSpan.events; + const lsEvents = loadSpan.events; + + assert.strictEqual(exporter.getFinishedSpans().length, 4); + assert.strictEqual(rootSpan.name, 'documentFetch'); + assert.strictEqual(rsEvents.length, 0); + + assert.strictEqual(fetchSpan.name, 'resourceFetch'); + assert.strictEqual(fsEvents.length, 0); + + assert.strictEqual(loadSpan.name, 'documentLoad'); + assert.deepEqual( + lsEvents.map(event => event.name), + ['firstPaint', 'firstContentfulPaint'] + ); + + done(); + }); + }); + + it('should ignore performance events if ignorePerformanceEvents is set to true', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + ignorePerformancePaintEvents: true, + }); + plugin.enable(); + + setTimeout(() => { + const loadSpan = exporter.getFinishedSpans()[3] as ReadableSpan; + const lsEvents = loadSpan.events; + + assert.strictEqual(exporter.getFinishedSpans().length, 4); + + assert.strictEqual(loadSpan.name, 'documentLoad'); + assert.notInclude( + lsEvents.map(event => event.name), + ['firstPaint', 'firstContentfulPaint'] + ); + + done(); + }); + }); + }); }); /**