Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a26bcac
[WIP] entities prototype
dyladan Apr 18, 2025
9ecc9cf
Fix compilation
dyladan Apr 21, 2025
1225700
Merge branch 'main' into res-prototype-v2
dyladan Apr 22, 2025
8d50933
Use interface for entity
dyladan May 2, 2025
5a32401
Merge branch 'res-prototype-v2' of github.com:dynatrace-oss-contrib/o…
dyladan May 2, 2025
73de5fb
Add impls
dyladan May 2, 2025
2f92a35
Merge remote-tracking branch 'origin/main' into res-prototype-v2
dyladan Jun 11, 2025
07850c8
Add entities to exporters
dyladan Jun 11, 2025
d3f1080
Add entities to e2e
dyladan Jun 11, 2025
9107ae5
maint: regenerate certs
dyladan Jun 11, 2025
6442107
Verify resource
dyladan Jun 11, 2025
e6185d3
Resource handling
dyladan Jun 11, 2025
6aefe6c
Disable autodetect resources
dyladan Jun 11, 2025
f22d391
Fix verification
dyladan Jun 11, 2025
f05673e
Lint
dyladan Jun 11, 2025
d17b2cd
Merge remote-tracking branch 'origin/main' into res-prototype-v2
dyladan Aug 28, 2025
b82a1e7
Merge remote-tracking branch 'origin/main' into res-prototype-v2
dyladan Sep 26, 2025
b2428f0
Save state
dyladan Jan 30, 2026
265923f
Add forEntity method to TracerProvider
dyladan Jan 30, 2026
047c180
Consolidate Entity types to API package
dyladan Jan 30, 2026
76fbc80
Add forEntity method to MeterProvider
dyladan Jan 30, 2026
d018fe4
Merge changes from upstream
dyladan Jan 30, 2026
85f03f4
Merge remote-tracking branch 'origin/main' into res-prototype-v3
dyladan Jan 30, 2026
99ca55d
Do not use proxy tracer constructor
dyladan Feb 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions api/src/common/Entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 { Attributes } from './Attributes';

export interface BindableProvider<T> {
forEntity(entity: Entity): T;
}

export type Entity = {
type: string;
identifier: Attributes;
attributes: Attributes;
schemaUrl?: string;
asyncAttributesPending: boolean;
waitForAsyncAttributes(): Promise<void>;
};
1 change: 1 addition & 0 deletions api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export { baggageEntryMetadataFromString } from './baggage/utils';
export type { Exception } from './common/Exception';
export type { HrTime, TimeInput } from './common/Time';
export type { Attributes, AttributeValue } from './common/Attributes';
export type { Entity } from './common/Entity';

// Context APIs
export { createContextKey, ROOT_CONTEXT } from './context/context';
Expand Down
3 changes: 2 additions & 1 deletion api/src/metrics/MeterProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@
* limitations under the License.
*/

import { BindableProvider } from '../common/Entity';
import { Meter, MeterOptions } from './Meter';

/**
* A registry for creating named {@link Meter}s.
*
* @since 1.3.0
*/
export interface MeterProvider {
export interface MeterProvider extends BindableProvider<MeterProvider> {
/**
* Returns a Meter, creating one if one with the given name, version, and
* schemaUrl pair is not already created.
Expand Down
5 changes: 5 additions & 0 deletions api/src/metrics/NoopMeterProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { Entity } from '../common/Entity';
import { Meter, MeterOptions } from './Meter';
import { MeterProvider } from './MeterProvider';
import { NOOP_METER } from './NoopMeter';
Expand All @@ -23,6 +24,10 @@ import { NOOP_METER } from './NoopMeter';
* for all calls to `getMeter`
*/
export class NoopMeterProvider implements MeterProvider {
forEntity(_entity: Entity): this {
return this;
}

getMeter(_name: string, _version?: string, _options?: MeterOptions): Meter {
return NOOP_METER;
}
Expand Down
5 changes: 5 additions & 0 deletions api/src/trace/NoopTracerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { Entity } from '../common/Entity';
import { NoopTracer } from './NoopTracer';
import { Tracer } from './tracer';
import { TracerOptions } from './tracer_options';
Expand All @@ -33,4 +34,8 @@ export class NoopTracerProvider implements TracerProvider {
): Tracer {
return new NoopTracer();
}

forEntity(_entity: Entity): TracerProvider {
return this;
}
}
18 changes: 17 additions & 1 deletion api/src/trace/ProxyTracerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { Entity } from '../common/Entity';
import { Tracer } from './tracer';
import { TracerProvider } from './tracer_provider';
import { ProxyTracer } from './ProxyTracer';
Expand All @@ -35,6 +36,7 @@ const NOOP_TRACER_PROVIDER = new NoopTracerProvider();
*/
export class ProxyTracerProvider implements TracerProvider {
private _delegate?: TracerProvider;
private _entity?: Entity;

/**
* Get a {@link ProxyTracer}
Expand All @@ -47,7 +49,11 @@ export class ProxyTracerProvider implements TracerProvider {
}

getDelegate(): TracerProvider {
return this._delegate ?? NOOP_TRACER_PROVIDER;
const delegate = this._delegate ?? NOOP_TRACER_PROVIDER;
if (this._entity && delegate !== NOOP_TRACER_PROVIDER) {
return delegate.forEntity(this._entity);
}
return delegate;
}

/**
Expand All @@ -64,4 +70,14 @@ export class ProxyTracerProvider implements TracerProvider {
): Tracer | undefined {
return this._delegate?.getTracer(name, version, options);
}

forEntity(entity: Entity): TracerProvider {
if (this._delegate) {
return this._delegate.forEntity(entity);
}
// Return a new proxy that will apply the entity when a delegate is set
const boundProxy = new ProxyTracerProvider();
boundProxy._entity = entity;
return boundProxy;
}
}
10 changes: 10 additions & 0 deletions api/src/trace/tracer_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { Entity } from '../common/Entity';
import { Tracer } from './tracer';
import { TracerOptions } from './tracer_options';

Expand All @@ -36,4 +37,13 @@ export interface TracerProvider {
* @returns Tracer A Tracer with the given name and version
*/
getTracer(name: string, version?: string, options?: TracerOptions): Tracer;

/**
* Creates a new TracerProvider with the same configuration but with the
* provided entity merged into the resource.
*
* @param entity The entity to merge into the resource
* @returns A new TracerProvider with the merged entity
*/
forEntity(entity: Entity): TracerProvider;
}
2 changes: 2 additions & 0 deletions api/test/common/proxy-implementations/proxy-tracer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ describe('ProxyTracer', function () {
getTracerStub = sandbox.stub().returns(new NoopTracer());
delegate = {
getTracer: getTracerStub,
forEntity: sandbox.stub().returnsThis(),
};
provider.setDelegate(delegate);
});
Expand Down Expand Up @@ -127,6 +128,7 @@ describe('ProxyTracer', function () {
getTracer() {
return delegateTracer;
},
forEntity: sandbox.stub().returnsThis(),
};
provider.setDelegate(delegate);
});
Expand Down
14 changes: 14 additions & 0 deletions e2e-tests/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
metrics,
} from '@opentelemetry/api';
import { logs } from '@opentelemetry/api-logs';
import { resourceFromDetectedResource } from '@opentelemetry/resources';

// Enable diagnostic logging (optional)
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);
Expand Down Expand Up @@ -56,11 +57,24 @@ const logExporter = new OTLPLogExporter({
});
const logRecordProcessors = [new SimpleLogRecordProcessor(logExporter)];

const resource = resourceFromDetectedResource({
entities: [
{
type: 'service',
identifier: { 'service.name': 'example-service' },
attributes: { 'service.version': '1.0.0' },
schemaUrl: 'https://opentelemetry.io/schemas/1.0.0/service',
},
],
});

// Set up OpenTelemetry SDK
const sdk = new NodeSDK({
spanProcessors,
metricReader,
logRecordProcessors,
resource,
autoDetectResources: false, // Disable automatic resource detection
});

async function main() {
Expand Down
26 changes: 26 additions & 0 deletions e2e-tests/verify.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@ for (const line of lines) {
if (parsed.resourceSpans) {
console.log('found span');
verifySpan(parsed.resourceSpans[0].scopeSpans[0].spans[0]);
verifyResource(parsed.resourceSpans[0].resource);
verifiedSpan = true;
}
if (parsed.resourceMetrics) {
console.log('found metric');
verifyMetric(parsed.resourceMetrics[0].scopeMetrics[0].metrics[0]);
verifyResource(parsed.resourceMetrics[0].resource);
verifiedMetric = true;
}
if (parsed.resourceLogs) {
console.log('found log');
verifyLog(parsed.resourceLogs[0].scopeLogs[0].logRecords[0]);
verifyResource(parsed.resourceLogs[0].resource);
verifiedLog = true;
}
}
Expand All @@ -56,6 +59,29 @@ if (!verifiedLog) {
process.exit(1);
}

function verifyResource(resource) {
if (!resource || !resource.attributes) {
console.error('Resource attributes are missing');
process.exit(1);
}
const name = resource.attributes.find(attr => attr.key === 'service.name');
if (!name || name.value.stringValue !== 'example-service') {
console.error(
`Expected service.name to be 'example-service', but got '${name?.value.stringValue}'`
);
process.exit(1);
}
const version = resource.attributes.find(
attr => attr.key === 'service.version'
);
if (!version || version.value.stringValue !== '1.0.0') {
console.error(
`Expected service.version to be '1.0.0', but got '${version?.value.stringValue}'`
);
process.exit(1);
}
}

function verifySpan(span) {
const expectedName = 'example-span';
if (span.name !== expectedName) {
Expand Down
9 changes: 7 additions & 2 deletions experimental/packages/api-logs/src/NoopLoggerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
* limitations under the License.
*/

import { LoggerProvider } from './types/LoggerProvider';
import { Entity } from '@opentelemetry/api';
import { NoopLogger } from './NoopLogger';
import { Logger } from './types/Logger';
import { LoggerOptions } from './types/LoggerOptions';
import { NoopLogger } from './NoopLogger';
import { LoggerProvider } from './types/LoggerProvider';

export class NoopLoggerProvider implements LoggerProvider {
getLogger(
Expand All @@ -27,6 +28,10 @@ export class NoopLoggerProvider implements LoggerProvider {
): Logger {
return new NoopLogger();
}

forEntity(_entity: Entity): LoggerProvider {
return this;
}
}

export const NOOP_LOGGER_PROVIDER = new NoopLoggerProvider();
16 changes: 16 additions & 0 deletions experimental/packages/api-logs/src/ProxyLoggerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import { Logger } from './types/Logger';
import { LoggerOptions } from './types/LoggerOptions';
import { NOOP_LOGGER_PROVIDER } from './NoopLoggerProvider';
import { ProxyLogger } from './ProxyLogger';
import { Entity } from '@opentelemetry/api';

export class ProxyLoggerProvider implements LoggerProvider {
private _delegate?: LoggerProvider;
private _boundEntity?: Entity;

getLogger(
name: string,
Expand All @@ -34,6 +36,16 @@ export class ProxyLoggerProvider implements LoggerProvider {
);
}

forEntity(entity: Entity): LoggerProvider {
const boundProvider = this._delegate?.forEntity(entity);
if (boundProvider) {
return boundProvider;
}
const proxyLoggerProvider = new ProxyLoggerProvider();
proxyLoggerProvider._boundEntity = entity;
return proxyLoggerProvider;
}

/**
* Get the delegate logger provider.
* Used by tests only.
Expand All @@ -59,6 +71,10 @@ export class ProxyLoggerProvider implements LoggerProvider {
version?: string | undefined,
options?: LoggerOptions | undefined
): Logger | undefined {
if (this._boundEntity) {
const boundProvider = this._delegate?.forEntity(this._boundEntity);
return boundProvider?.getLogger(name, version, options);
}
return this._delegate?.getLogger(name, version, options);
}
}
3 changes: 3 additions & 0 deletions experimental/packages/api-logs/src/types/LoggerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { Entity } from '@opentelemetry/api';
import { Logger } from './Logger';
import { LoggerOptions } from './LoggerOptions';

Expand All @@ -31,4 +32,6 @@ export interface LoggerProvider {
* @returns Logger A Logger with the given name and version
*/
getLogger(name: string, version?: string, options?: LoggerOptions): Logger;

forEntity(entity: Entity): LoggerProvider;
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ describe('ProxyLogger', () => {
getLoggerStub = sandbox.stub().returns(new NoopLogger());
delegate = {
getLogger: getLoggerStub,
forEntity(entity) {
return this;
},
};
provider._setDelegate(delegate);
});
Expand Down Expand Up @@ -100,6 +103,9 @@ describe('ProxyLogger', () => {
getLogger() {
return delegateLogger;
},
forEntity() {
return this;
},
};
provider._setDelegate(delegateProvider);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe('HttpInstrumentation', () => {
.returns(trace.wrapSpanContext(INVALID_SPAN_CONTEXT));
return { startSpan: startSpanStub } as any;
},
forEntity: () => provider,
};
nock.cleanAll();
nock.enableNetConnect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ describe('HttpsInstrumentation', () => {
.returns(trace.wrapSpanContext(INVALID_SPAN_CONTEXT));
return { startSpan: startSpanStub } as any;
},
forEntity: () => provider,
};
nock.cleanAll();
nock.enableNetConnect();
Expand Down
Loading
Loading