SDK Resource (#846)

* feat: add Resource.empty() method

* feat: add resource to BasicTracerProvider and assign to Spans

* feat: add Resource.createLibraryResource method

* refactor: rename LIBARY_RESOURCE -> TELEMETRY_SDK_RESOURCE

* feat: add resource to ReadableSpan interface

* feat: add Resource to NodeTracerProvider

* feat: add Resource to WebTracerProvider

* refactor: move resource-assertions

* feat: add Resource to instruments

* refactor: add SDK_INFO to core; simplify SDK resource creation

* chore: docs and cleanup

* docs: no need to update the copyright

* chore: move resources to devDependencies where applicable

* refactor: add resource to TraceConfig

* refactor: add resource to MeterConfig

* refactor: change resource visibility on Meter

* refactor: move resource-assertions to test/util
This commit is contained in:
Matthew Wear 2020-03-11 13:41:22 -07:00 committed by GitHub
parent 69d738c21b
commit abd191bef3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 329 additions and 36 deletions

View File

@ -3,6 +3,10 @@
"version": "0.4.0",
"description": "OpenTelemetry base provides base code for the SDK packages",
"main": "build/src/index.js",
"browser": {
"./src/platform/index.ts": "./src/platform/browser/index.ts",
"./build/src/platform/index.js": "./build/src/platform/browser/index.js"
},
"types": "build/src/index.d.ts",
"repository": "open-telemetry/opentelemetry-js",
"scripts": {

View File

@ -15,3 +15,4 @@
*/
export * from './ExportResult';
export * from './platform';

View File

@ -0,0 +1,25 @@
/**
* Copyright 2020, 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 { VERSION } from '../../version';
/** Constants describing the SDK in use */
export const SDK_INFO = {
NAME: 'opentelemetry',
RUNTIME: 'browser',
LANGUAGE: 'webjs',
VERSION: VERSION,
};

View File

@ -0,0 +1,17 @@
/*!
* Copyright 2020, 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.
*/
export * from './constants';

View File

@ -0,0 +1,20 @@
/*!
* Copyright 2020, 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.
*/
// Use the node platform by default. The "browser" field of package.json is used
// to override this file to use `./browser/index.ts` when packaged with
// webpack, Rollup, etc.
export * from './node';

View File

@ -0,0 +1,25 @@
/**
* Copyright 2020, 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 { VERSION } from '../../version';
/** Constants describing the SDK in use */
export const SDK_INFO = {
NAME: 'opentelemetry',
RUNTIME: 'node',
LANGUAGE: 'nodejs',
VERSION: VERSION,
};

View File

@ -0,0 +1,17 @@
/*!
* Copyright 2020, 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.
*/
export * from './constants';

View File

@ -50,6 +50,7 @@
},
"devDependencies": {
"@babel/core": "^7.6.0",
"@opentelemetry/resources": "^0.4.0",
"@types/mocha": "^5.2.5",
"@types/node": "^12.6.8",
"@types/sinon": "^7.0.13",

View File

@ -17,6 +17,7 @@
import { TraceFlags } from '@opentelemetry/api';
import * as core from '@opentelemetry/core';
import { ReadableSpan } from '@opentelemetry/tracing';
import { Resource } from '@opentelemetry/resources';
import * as assert from 'assert';
import * as transform from '../src/transform';
import * as collectorTypes from '../src/types';
@ -68,6 +69,7 @@ export const mockedReadableSpan: ReadableSpan = {
},
],
duration: [0, 8885000],
resource: Resource.empty(),
};
export function ensureSpanIsCorrect(span: collectorTypes.Span) {

View File

@ -40,6 +40,7 @@
"access": "public"
},
"devDependencies": {
"@opentelemetry/resources": "^0.4.0",
"@types/mocha": "^5.2.7",
"@types/node": "^12.6.9",
"codecov": "^3.6.1",

View File

@ -22,6 +22,7 @@ import { ThriftProcess } from '../src/types';
import { ReadableSpan } from '@opentelemetry/tracing';
import { ExportResult } from '@opentelemetry/base';
import { TraceFlags } from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
describe('JaegerExporter', () => {
describe('constructor', () => {
@ -127,6 +128,7 @@ describe('JaegerExporter', () => {
links: [],
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
};
exporter.export([readableSpan], (result: ExportResult) => {

View File

@ -17,6 +17,7 @@
import * as assert from 'assert';
import { spanToThrift } from '../src/transform';
import { ReadableSpan } from '@opentelemetry/tracing';
import { Resource } from '@opentelemetry/resources';
import * as types from '@opentelemetry/api';
import { ThriftUtils, Utils, ThriftReferenceType } from '../src/types';
import { hrTimeToMicroseconds } from '@opentelemetry/core';
@ -69,6 +70,7 @@ describe('transform', () => {
},
],
duration: [32, 800000000],
resource: Resource.empty(),
};
const thriftSpan = spanToThrift(readableSpan);
@ -143,6 +145,7 @@ describe('transform', () => {
links: [],
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
};
const thriftSpan = spanToThrift(readableSpan);
@ -207,6 +210,7 @@ describe('transform', () => {
],
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
};
const thriftSpan = spanToThrift(readableSpan);
@ -245,6 +249,7 @@ describe('transform', () => {
links: [],
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
};
const thriftSpan = spanToThrift(readableSpan);

View File

@ -41,6 +41,7 @@
"access": "public"
},
"devDependencies": {
"@opentelemetry/resources": "^0.4.0",
"@types/mocha": "^5.2.7",
"@types/nock": "^11.1.0",
"@types/node": "^12.6.9",

View File

@ -17,6 +17,7 @@
import { ExportResult } from '@opentelemetry/base';
import { ConsoleLogger, LogLevel } from '@opentelemetry/core';
import { ReadableSpan } from '@opentelemetry/tracing';
import { Resource } from '@opentelemetry/resources';
import * as types from '@opentelemetry/api';
import * as assert from 'assert';
import * as nock from 'nock';
@ -121,6 +122,7 @@ describe('Stackdriver Trace Exporter', () => {
isRemote: true,
},
status: { code: types.CanonicalCode.OK },
resource: Resource.empty(),
};
const result = await new Promise((resolve, reject) => {
@ -155,6 +157,7 @@ describe('Stackdriver Trace Exporter', () => {
isRemote: true,
},
status: { code: types.CanonicalCode.OK },
resource: Resource.empty(),
};
getClientShouldFail = true;
@ -188,6 +191,7 @@ describe('Stackdriver Trace Exporter', () => {
isRemote: true,
},
status: { code: types.CanonicalCode.OK },
resource: Resource.empty(),
};
batchWriteShouldFail = true;
@ -219,6 +223,7 @@ describe('Stackdriver Trace Exporter', () => {
isRemote: true,
},
status: { code: types.CanonicalCode.OK },
resource: Resource.empty(),
};
await exporter['_projectId'];

View File

@ -16,6 +16,7 @@
import { VERSION as CORE_VERSION } from '@opentelemetry/core';
import { ReadableSpan } from '@opentelemetry/tracing';
import { Resource } from '@opentelemetry/resources';
import * as types from '@opentelemetry/api';
import * as assert from 'assert';
import { getReadableSpanTransformer } from '../src/transform';
@ -50,6 +51,7 @@ describe('transform', () => {
name: 'my-span',
spanContext,
status: { code: types.CanonicalCode.OK },
resource: Resource.empty(),
};
});

View File

@ -39,6 +39,7 @@
"access": "public"
},
"devDependencies": {
"@opentelemetry/resources": "^0.4.0",
"@types/mocha": "^5.2.7",
"@types/nock": "^10.0.3",
"@types/node": "^12.6.9",

View File

@ -20,6 +20,7 @@ import { ReadableSpan } from '@opentelemetry/tracing';
import { ExportResult } from '@opentelemetry/base';
import { NoopLogger, hrTimeToMicroseconds } from '@opentelemetry/core';
import * as types from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
import { ZipkinExporter } from '../src';
import * as zipkinTypes from '../src/types';
import { OT_REQUEST_HEADER } from '../src/utils';
@ -48,6 +49,7 @@ function getReadableSpan() {
attributes: {},
links: [],
events: [],
resource: Resource.empty(),
};
return readableSpan;
}
@ -154,6 +156,7 @@ describe('ZipkinExporter', () => {
attributes: { key3: 'value3' },
},
],
resource: Resource.empty(),
};
const span2: ReadableSpan = {
name: 'my-span',
@ -173,6 +176,7 @@ describe('ZipkinExporter', () => {
attributes: {},
links: [],
events: [],
resource: Resource.empty(),
};
const exporter = new ZipkinExporter({

View File

@ -59,6 +59,7 @@
"dependencies": {
"@opentelemetry/api": "^0.4.0",
"@opentelemetry/base": "^0.4.0",
"@opentelemetry/core": "^0.4.0"
"@opentelemetry/core": "^0.4.0",
"@opentelemetry/resources": "^0.4.0"
}
}

View File

@ -16,6 +16,7 @@
import * as types from '@opentelemetry/api';
import { ConsoleLogger } from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import { BaseBoundInstrument } from './BoundInstrument';
import { Metric, CounterMetric, MeasureMetric, ObserverMetric } from './Metric';
import {
@ -36,6 +37,7 @@ export class Meter implements types.Meter {
private readonly _logger: types.Logger;
private readonly _metrics = new Map<string, Metric<BaseBoundInstrument>>();
private readonly _batcher: Batcher;
private readonly _resource: Resource;
readonly labels = Meter.labels;
/**
@ -44,6 +46,7 @@ export class Meter implements types.Meter {
constructor(config: MeterConfig = DEFAULT_CONFIG) {
this._logger = config.logger || new ConsoleLogger(config.logLevel);
this._batcher = new UngroupedBatcher();
this._resource = config.resource || Resource.createTelemetrySDKResource();
// start the push controller
const exporter = config.exporter || new NoopExporter();
const interval = config.interval;
@ -73,7 +76,7 @@ export class Meter implements types.Meter {
...options,
};
const measure = new MeasureMetric(name, opt, this._batcher);
const measure = new MeasureMetric(name, opt, this._batcher, this._resource);
this._registerMetric(name, measure);
return measure;
}
@ -102,7 +105,7 @@ export class Meter implements types.Meter {
...DEFAULT_METRIC_OPTIONS,
...options,
};
const counter = new CounterMetric(name, opt, this._batcher);
const counter = new CounterMetric(name, opt, this._batcher, this._resource);
this._registerMetric(name, counter);
return counter;
}
@ -129,7 +132,12 @@ export class Meter implements types.Meter {
...DEFAULT_METRIC_OPTIONS,
...options,
};
const observer = new ObserverMetric(name, opt, this._batcher);
const observer = new ObserverMetric(
name,
opt,
this._batcher,
this._resource
);
this._registerMetric(name, observer);
return observer;
}

View File

@ -16,6 +16,7 @@
import { ConsoleLogger } from '@opentelemetry/core';
import * as types from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
import { Meter } from '.';
import { DEFAULT_CONFIG, MeterConfig } from './types';
@ -24,6 +25,7 @@ import { DEFAULT_CONFIG, MeterConfig } from './types';
*/
export class MeterProvider implements types.MeterProvider {
private readonly _meters: Map<string, Meter> = new Map();
readonly resource: Resource = Resource.createTelemetrySDKResource();
readonly logger: types.Logger;
constructor(private _config: MeterConfig = DEFAULT_CONFIG) {

View File

@ -15,6 +15,7 @@
*/
import * as types from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
import {
BoundCounter,
BaseBoundInstrument,
@ -39,7 +40,8 @@ export abstract class Metric<T extends BaseBoundInstrument>
constructor(
private readonly _name: string,
private readonly _options: MetricOptions,
private readonly _kind: MetricKind
private readonly _kind: MetricKind,
readonly resource: Resource
) {
this._monotonic = _options.monotonic;
this._disabled = _options.disabled;
@ -108,9 +110,10 @@ export class CounterMetric extends Metric<BoundCounter>
constructor(
name: string,
options: MetricOptions,
private readonly _batcher: Batcher
private readonly _batcher: Batcher,
resource: Resource
) {
super(name, options, MetricKind.COUNTER);
super(name, options, MetricKind.COUNTER, resource);
}
protected _makeInstrument(labelSet: types.LabelSet): BoundCounter {
return new BoundCounter(
@ -141,9 +144,10 @@ export class MeasureMetric extends Metric<BoundMeasure>
constructor(
name: string,
options: MetricOptions,
private readonly _batcher: Batcher
private readonly _batcher: Batcher,
resource: Resource
) {
super(name, options, MetricKind.MEASURE);
super(name, options, MetricKind.MEASURE, resource);
this._absolute = options.absolute !== undefined ? options.absolute : true; // Absolute default is true
}
@ -172,9 +176,10 @@ export class ObserverMetric extends Metric<BoundObserver>
constructor(
name: string,
options: MetricOptions,
private readonly _batcher: Batcher
private readonly _batcher: Batcher,
resource: Resource
) {
super(name, options, MetricKind.OBSERVER);
super(name, options, MetricKind.OBSERVER, resource);
}
protected _makeInstrument(labelSet: types.LabelSet): BoundObserver {

View File

@ -17,6 +17,7 @@
import { LogLevel } from '@opentelemetry/core';
import { Logger, ValueType } from '@opentelemetry/api';
import { MetricExporter } from './export/types';
import { Resource } from '@opentelemetry/resources';
/** Options needed for SDK metric creation. */
export interface MetricOptions {
@ -64,6 +65,9 @@ export interface MeterConfig {
/** Metric collect interval */
interval?: number;
/** Resource associated with metric telemetry */
resource?: Resource;
}
/** Default Meter configuration. */

View File

@ -35,6 +35,7 @@ import {
ObserverAggregator,
} from '../src/export/Aggregator';
import { ValueType } from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
describe('Meter', () => {
let meter: Meter;
@ -88,6 +89,11 @@ describe('Meter', () => {
assert.strictEqual(record1.aggregator.value(), 20);
});
it('should return counter with resource', () => {
const counter = meter.createCounter('name') as CounterMetric;
assert.ok(counter.resource instanceof Resource);
});
describe('.bind()', () => {
it('should create a counter instrument', () => {
const counter = meter.createCounter('name') as CounterMetric;
@ -275,6 +281,11 @@ describe('Meter', () => {
assert.strictEqual((measure as MeasureMetric)['_absolute'], false);
});
it('should return a measure with resource', () => {
const measure = meter.createMeasure('name') as MeasureMetric;
assert.ok(measure.resource instanceof Resource);
});
describe('names', () => {
it('should return no op metric if name is an empty string', () => {
const measure = meter.createMeasure('');
@ -457,6 +468,11 @@ describe('Meter', () => {
ensureMetric(metric3);
ensureMetric(metric4);
});
it('should return an observer with resource', () => {
const observer = meter.createObserver('name') as ObserverMetric;
assert.ok(observer.resource instanceof Resource);
});
});
describe('#getMetrics', () => {

View File

@ -41,6 +41,7 @@
"access": "public"
},
"devDependencies": {
"@opentelemetry/resources": "^0.4.0",
"@types/mocha": "^5.2.5",
"@types/node": "^12.6.8",
"@opentelemetry/scope-base": "^0.4.0",

View File

@ -24,6 +24,7 @@ import {
} from '@opentelemetry/core';
import { AsyncHooksScopeManager } from '@opentelemetry/scope-async-hooks';
import { Span } from '@opentelemetry/tracing';
import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources';
import * as assert from 'assert';
import * as path from 'path';
import { ScopeManager } from '../../opentelemetry-scope-base/build/src';
@ -158,6 +159,19 @@ describe('NodeTracerProvider', () => {
assert.ok(span instanceof Span);
assert.deepStrictEqual(span.attributes, defaultAttributes);
});
it('should assign resource to span', () => {
provider = new NodeTracerProvider({
logger: new NoopLogger(),
});
const span = provider.getTracer('default').startSpan('my-span') as Span;
assert.ok(span);
assert.ok(span.resource instanceof Resource);
assert.equal(
span.resource.labels[TELEMETRY_SDK_RESOURCE.LANGUAGE],
'nodejs'
);
});
});
describe('.getCurrentSpan()', () => {

View File

@ -54,6 +54,7 @@
"typescript": "3.7.2"
},
"dependencies": {
"@opentelemetry/api": "^0.4.0"
"@opentelemetry/api": "^0.4.0",
"@opentelemetry/base": "^0.4.0"
}
}

View File

@ -14,11 +14,34 @@
* limitations under the License.
*/
import { SDK_INFO } from '@opentelemetry/base';
import { TELEMETRY_SDK_RESOURCE } from './constants';
/**
* A Resource describes the entity for which a signals (metrics or trace) are
* collected.
*/
export class Resource {
static readonly EMPTY = new Resource({});
/**
* Returns an empty Resource
*/
static empty(): Resource {
return Resource.EMPTY;
}
/**
* Returns a Resource that indentifies the SDK in use.
*/
static createTelemetrySDKResource(): Resource {
return new Resource({
[TELEMETRY_SDK_RESOURCE.LANGUAGE]: SDK_INFO.LANGUAGE,
[TELEMETRY_SDK_RESOURCE.NAME]: SDK_INFO.NAME,
[TELEMETRY_SDK_RESOURCE.VERSION]: SDK_INFO.VERSION,
});
}
constructor(
/**
* A dictionary of labels with string keys and values that provide information

View File

@ -98,15 +98,15 @@ export const K8S_RESOURCE = {
};
/** Attributes describing the telemetry library. */
export const LIBRARY_RESOURCE = {
export const TELEMETRY_SDK_RESOURCE = {
/** The name of the telemetry library. */
NAME: 'library.name',
NAME: 'telemetry.sdk.name',
/** The language of telemetry library and of the code instrumented with it. */
LANGUAGE: 'library.language',
LANGUAGE: 'telemetry.sdk.language',
/** The version string of the library. */
VERSION: 'library.version',
/** The version string of the telemetry library */
VERSION: 'telemetry.sdk.version',
};
/** Attributes describing a service instance. */

View File

@ -14,8 +14,10 @@
* limitations under the License.
*/
import { SDK_INFO } from '@opentelemetry/base';
import * as assert from 'assert';
import { Resource } from '../src/Resource';
import { assertTelemetrySDKResource } from './util/resource-assertions';
describe('Resource', () => {
const resource1 = new Resource({
@ -86,4 +88,26 @@ describe('Resource', () => {
assert.equal(resource.labels['custom.number'], 42);
assert.equal(resource.labels['custom.boolean'], true);
});
describe('.empty()', () => {
it('should return an empty resource', () => {
const resource = Resource.empty();
assert.equal(Object.entries(resource.labels), 0);
});
it('should return the same empty resource', () => {
assert.strictEqual(Resource.empty(), Resource.empty());
});
});
describe('.createTelemetrySDKResource()', () => {
it('should return a telemetry SDK resource', () => {
const resource = Resource.createTelemetrySDKResource();
assertTelemetrySDKResource(resource, {
language: SDK_INFO.LANGUAGE,
name: SDK_INFO.NAME,
version: SDK_INFO.VERSION,
});
});
});
});

View File

@ -14,13 +14,14 @@
* limitations under the License.
*/
import { SDK_INFO } from '@opentelemetry/base';
import { Resource } from '../src/Resource';
import {
CLOUD_RESOURCE,
CONTAINER_RESOURCE,
HOST_RESOURCE,
K8S_RESOURCE,
LIBRARY_RESOURCE,
TELEMETRY_SDK_RESOURCE,
SERVICE_RESOURCE,
} from '../src/constants';
import {
@ -28,7 +29,7 @@ import {
assertContainerResource,
assertHostResource,
assertK8sResource,
assertLibraryResource,
assertTelemetrySDKResource,
assertServiceResource,
} from './util/resource-assertions';
@ -131,19 +132,23 @@ describe('assertK8sResource', () => {
});
});
describe('assertLibraryResource', () => {
it('requires one library label', () => {
const resource = new Resource({ [LIBRARY_RESOURCE.NAME]: 'opentelemetry' });
assertLibraryResource(resource, {});
describe('assertTelemetrySDKResource', () => {
it('uses default validations', () => {
const resource = new Resource({
[TELEMETRY_SDK_RESOURCE.NAME]: SDK_INFO.NAME,
[TELEMETRY_SDK_RESOURCE.LANGUAGE]: SDK_INFO.LANGUAGE,
[TELEMETRY_SDK_RESOURCE.VERSION]: SDK_INFO.VERSION,
});
assertTelemetrySDKResource(resource, {});
});
it('validates optional labels', () => {
const resource = new Resource({
[LIBRARY_RESOURCE.NAME]: 'opentelemetry',
[LIBRARY_RESOURCE.LANGUAGE]: 'nodejs',
[LIBRARY_RESOURCE.VERSION]: '0.1.0',
[TELEMETRY_SDK_RESOURCE.NAME]: 'opentelemetry',
[TELEMETRY_SDK_RESOURCE.LANGUAGE]: 'nodejs',
[TELEMETRY_SDK_RESOURCE.VERSION]: '0.1.0',
});
assertLibraryResource(resource, {
assertTelemetrySDKResource(resource, {
name: 'opentelemetry',
language: 'nodejs',
version: '0.1.0',

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
import { SDK_INFO } from '@opentelemetry/base';
import * as assert from 'assert';
import { Resource } from '../../src/Resource';
import {
@ -21,9 +22,10 @@ import {
CONTAINER_RESOURCE,
HOST_RESOURCE,
K8S_RESOURCE,
LIBRARY_RESOURCE,
TELEMETRY_SDK_RESOURCE,
SERVICE_RESOURCE,
} from '../../src/constants';
/**
* Test utility method to validate a cloud resource
*
@ -180,12 +182,12 @@ export const assertK8sResource = (
};
/**
* Test utility method to validate a library resource
* Test utility method to validate a telemetry sdk resource
*
* @param resource the Resource to validate
* @param validations validations for the resource labels
*/
export const assertLibraryResource = (
export const assertTelemetrySDKResource = (
resource: Resource,
validations: {
name?: string;
@ -193,20 +195,26 @@ export const assertLibraryResource = (
version?: string;
}
) => {
assertHasOneLabel(LIBRARY_RESOURCE, resource);
const defaults = {
name: SDK_INFO.NAME,
language: SDK_INFO.LANGUAGE,
version: SDK_INFO.VERSION,
};
validations = { ...defaults, ...validations };
if (validations.name)
assert.strictEqual(
resource.labels[LIBRARY_RESOURCE.NAME],
resource.labels[TELEMETRY_SDK_RESOURCE.NAME],
validations.name
);
if (validations.language)
assert.strictEqual(
resource.labels[LIBRARY_RESOURCE.LANGUAGE],
resource.labels[TELEMETRY_SDK_RESOURCE.LANGUAGE],
validations.language
);
if (validations.version)
assert.strictEqual(
resource.labels[LIBRARY_RESOURCE.VERSION],
resource.labels[TELEMETRY_SDK_RESOURCE.VERSION],
validations.version
);
};

View File

@ -76,6 +76,7 @@
"@opentelemetry/api": "^0.4.0",
"@opentelemetry/base": "^0.4.0",
"@opentelemetry/core": "^0.4.0",
"@opentelemetry/resources": "^0.4.0",
"@opentelemetry/scope-base": "^0.4.0"
}
}

View File

@ -21,6 +21,7 @@ import { DEFAULT_CONFIG } from './config';
import { MultiSpanProcessor } from './MultiSpanProcessor';
import { NoopSpanProcessor } from './NoopSpanProcessor';
import { SDKRegistrationConfig, TracerConfig } from './types';
import { Resource } from '@opentelemetry/resources';
/**
* This class represents a basic tracer provider which platform libraries can extend
@ -31,9 +32,11 @@ export class BasicTracerProvider implements api.TracerProvider {
activeSpanProcessor = new NoopSpanProcessor();
readonly logger: api.Logger;
readonly resource: Resource;
constructor(private _config: TracerConfig = DEFAULT_CONFIG) {
this.logger = _config.logger || new ConsoleLogger(_config.logLevel);
this.resource = _config.resource || Resource.createTelemetrySDKResource();
}
getTracer(name: string, version = '*', config?: TracerConfig): Tracer {

View File

@ -21,6 +21,7 @@ import {
isTimeInput,
timeInputToHrTime,
} from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import { ReadableSpan } from './export/ReadableSpan';
import { Tracer } from './Tracer';
import { SpanProcessor } from './SpanProcessor';
@ -39,6 +40,7 @@ export class Span implements types.Span, ReadableSpan {
readonly links: types.Link[] = [];
readonly events: types.TimedEvent[] = [];
readonly startTime: types.HrTime;
readonly resource: Resource;
name: string;
status: types.Status = {
code: types.CanonicalCode.OK,
@ -66,6 +68,7 @@ export class Span implements types.Span, ReadableSpan {
this.kind = kind;
this.links = links;
this.startTime = timeInputToHrTime(startTime);
this.resource = parentTracer.resource;
this._logger = parentTracer.logger;
this._traceParams = parentTracer.getActiveTraceParams();
this._spanProcessor = parentTracer.getActiveSpanProcessor();

View File

@ -25,6 +25,7 @@ import {
randomTraceId,
setActiveSpan,
} from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import { BasicTracerProvider } from './BasicTracerProvider';
import { DEFAULT_CONFIG } from './config';
import { Span } from './Span';
@ -38,6 +39,7 @@ export class Tracer implements api.Tracer {
private readonly _defaultAttributes: api.Attributes;
private readonly _sampler: api.Sampler;
private readonly _traceParams: TraceParams;
readonly resource: Resource;
readonly logger: api.Logger;
/**
@ -51,6 +53,7 @@ export class Tracer implements api.Tracer {
this._defaultAttributes = localConfig.defaultAttributes;
this._sampler = localConfig.sampler;
this._traceParams = localConfig.traceParams;
this.resource = _tracerProvider.resource;
this.logger = config.logger || new ConsoleLogger(config.logLevel);
}

View File

@ -23,6 +23,7 @@ import {
SpanContext,
TimedEvent,
} from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
export interface ReadableSpan {
readonly name: string;
@ -37,4 +38,5 @@ export interface ReadableSpan {
readonly events: TimedEvent[];
readonly duration: HrTime;
readonly ended: boolean;
readonly resource: Resource;
}

View File

@ -22,6 +22,7 @@ import {
} from '@opentelemetry/api';
import { LogLevel } from '@opentelemetry/core';
import { ScopeManager } from '@opentelemetry/scope-base';
import { Resource } from '@opentelemetry/resources';
/**
* TracerConfig provides an interface for configuring a Basic Tracer.
@ -48,6 +49,9 @@ export interface TracerConfig {
/** Trace Parameters */
traceParams?: TraceParams;
/** Resource associated with trace telemetry */
resource?: Resource;
}
/**

View File

@ -24,6 +24,7 @@ import {
setExtractedSpanContext,
TraceState,
} from '@opentelemetry/core';
import { Resource } from '@opentelemetry/resources';
import { NoopScopeManager, ScopeManager } from '@opentelemetry/scope-base';
import * as assert from 'assert';
import { BasicTracerProvider, Span } from '../src';
@ -305,6 +306,13 @@ describe('BasicTracerProvider', () => {
assert.ok(span instanceof Span);
assert.deepStrictEqual(span.attributes, defaultAttributes);
});
it('should assign a resource', () => {
const tracer = new BasicTracerProvider().getTracer('default');
const span = tracer.startSpan('my-span') as Span;
assert.ok(span);
assert.ok(span.resource instanceof Resource);
});
});
describe('.getCurrentSpan()', () => {
@ -342,4 +350,11 @@ describe('BasicTracerProvider', () => {
return patchedFn();
});
});
describe('.resource', () => {
it('should return a Resource', () => {
const tracerProvider = new BasicTracerProvider();
assert.ok(tracerProvider.resource instanceof Resource);
});
});
});

View File

@ -43,6 +43,7 @@
},
"devDependencies": {
"@babel/core": "^7.6.0",
"@opentelemetry/resources": "^0.4.0",
"@opentelemetry/scope-zone": "^0.4.0",
"@types/jquery": "^3.3.31",
"@types/mocha": "^5.2.5",

View File

@ -15,10 +15,11 @@
*/
import { context } from '@opentelemetry/api';
import { BasePlugin } from '@opentelemetry/core';
import { BasePlugin, NoopLogger } from '@opentelemetry/core';
import { ScopeManager } from '@opentelemetry/scope-base';
import { ZoneScopeManager } from '@opentelemetry/scope-zone';
import { Tracer } from '@opentelemetry/tracing';
import { Tracer, Span } from '@opentelemetry/tracing';
import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources';
import * as assert from 'assert';
import * as sinon from 'sinon';
import { WebTracerConfig } from '../src';
@ -116,5 +117,20 @@ describe('WebTracerProvider', () => {
});
});
});
describe('.startSpan()', () => {
it('should assign resource to span', () => {
const provider = new WebTracerProvider({
logger: new NoopLogger(),
});
const span = provider.getTracer('default').startSpan('my-span') as Span;
assert.ok(span);
assert.ok(span.resource instanceof Resource);
assert.equal(
span.resource.labels[TELEMETRY_SDK_RESOURCE.LANGUAGE],
'webjs'
);
});
});
});
});