Skip to content

Commit

Permalink
feat(opencensus-shim) add mapping logic and propagation shim
Browse files Browse the repository at this point in the history
  • Loading branch information
aabmass committed Apr 24, 2023
1 parent 89af775 commit ad655a9
Show file tree
Hide file tree
Showing 5 changed files with 408 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"prepublishOnly": "npm run compile",
"compile": "tsc --build",
"clean": "tsc --build --clean",
"tdd": "npm run test -- --extension ts --watch",
"test": "nyc ts-mocha -p tsconfig.json test/**/*.test.ts",
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../../",
"lint": "eslint . --ext .ts",
Expand Down Expand Up @@ -53,6 +54,8 @@
"codecov": "3.8.3",
"mocha": "10.0.0",
"nyc": "15.1.0",
"sinon": "15.0.0",
"@types/sinon": "10.0.13",
"rimraf": "4.1.2",
"ts-mocha": "10.0.0",
"typescript": "4.4.4"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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 * as oc from '@opencensus/core';

import {
context,
propagation,
trace,
TextMapGetter,
TextMapSetter,
} from '@opentelemetry/api';
import { mapSpanContext, reverseMapSpanContext } from './transform';

class Getter implements TextMapGetter<void> {
constructor(private ocGetter: oc.HeaderGetter) {}
keys(): string[] {
return [];
}
get(carrier: void, key: string) {
return this.ocGetter.getHeader(key);
}
}

class Setter implements TextMapSetter<void> {
constructor(private ocSetter: oc.HeaderSetter) {}
set(carrier: void, key: string, value: string): void {
this.ocSetter.setHeader(key, value);
}
}

/**
* Bridges OpenCensus propagation API into OpenTelemetry. The global OTel propagators will be
* used if none is provided
*/
export const shimPropagation: oc.Propagation = {
extract(getter: oc.HeaderGetter): oc.SpanContext | null {
const extracted = propagation.extract(
context.active(),
null,
new Getter(getter)
);

const otelSc = trace.getSpanContext(extracted);
return otelSc ? reverseMapSpanContext(otelSc) : null;
},

inject(setter: oc.HeaderSetter, spanContext: oc.SpanContext): void {
const ctx = trace.setSpanContext(
context.active(),
mapSpanContext(spanContext)
);
propagation.inject(ctx, null, new Setter(setter));
},

generate(): oc.SpanContext {
throw new Error('Function not implemented.');
},
};
105 changes: 105 additions & 0 deletions experimental/packages/opentelemetry-shim-opencensus/src/transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* 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 * as oc from '@opencensus/core';
import {
Attributes,
SpanContext,
SpanKind,
TimeInput,
diag,
} from '@opentelemetry/api';
import { TraceState } from '@opentelemetry/core';

function exhaust(value: never) {
diag.warn('Could not handle enum value %s', value);
}

export function mapSpanKind(
kind: oc.SpanKind | undefined
): SpanKind | undefined {
switch (kind) {
case undefined:
return undefined;
case oc.SpanKind.UNSPECIFIED:
return SpanKind.INTERNAL;
case oc.SpanKind.CLIENT:
return SpanKind.CLIENT;
case oc.SpanKind.SERVER:
return SpanKind.SERVER;
default:
exhaust(kind);
return undefined;
}
}

export function mapSpanContext({
spanId,
traceId,
options,
traceState,
}: oc.SpanContext): SpanContext {
return {
spanId,
traceId,
traceFlags: options ?? 0,
traceState:
traceState === undefined ? undefined : new TraceState(traceState),
};
}

export function reverseMapSpanContext({
spanId,
traceId,
traceFlags,
traceState,
}: SpanContext): oc.SpanContext {
return {
spanId: spanId,
traceId: traceId,
options: traceFlags,
traceState: traceState?.serialize(),
};
}

// Copied from Java
// https://github.com/open-telemetry/opentelemetry-java/blob/0d3a04669e51b33ea47b29399a7af00012d25ccb/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/SpanConverter.java#L24-L27
const MESSAGE_EVENT_ATTRIBUTE_KEY_TYPE = 'message.event.type';
const MESSAGE_EVENT_ATTRIBUTE_KEY_SIZE_UNCOMPRESSED =
'message.event.size.uncompressed';
const MESSAGE_EVENT_ATTRIBUTE_KEY_SIZE_COMPRESSED =
'message.event.size.compressed';

export function mapMessageEvent(
type: oc.MessageEventType,
id: number,
timestamp?: number,
uncompressedSize?: number,
compressedSize?: number
): [string, Attributes, TimeInput | undefined] {
const attributes: Attributes = {
[MESSAGE_EVENT_ATTRIBUTE_KEY_TYPE]: oc.MessageEventType[type],
};
if (uncompressedSize !== undefined) {
attributes[MESSAGE_EVENT_ATTRIBUTE_KEY_SIZE_UNCOMPRESSED] =
uncompressedSize;
}
if (compressedSize !== undefined) {
attributes[MESSAGE_EVENT_ATTRIBUTE_KEY_SIZE_COMPRESSED] = compressedSize;
}

return [id.toString(), attributes, timestamp];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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 { shimPropagation } from '../src/propagation';

import * as oc from '@opencensus/core';
import { propagation } from '@opentelemetry/api';
import { W3CTraceContextPropagator } from '@opentelemetry/core';
import * as assert from 'assert';
import * as sinon from 'sinon';

const dummyGetterWithHeader: oc.HeaderGetter = {
getHeader(name) {
if (name === 'traceparent') {
return '00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01';
}
return undefined;
},
};
const dummyGetterWithoutHeader: oc.HeaderGetter = {
getHeader() {
return undefined;
},
};

describe('propagation', () => {
describe('shimPropagation', () => {
beforeEach(() => {
propagation.setGlobalPropagator(new W3CTraceContextPropagator());
});
afterEach(() => {
propagation.disable();
});

describe('extract', () => {
it('should extract when header is available', () => {
assert.deepStrictEqual(shimPropagation.extract(dummyGetterWithHeader), {
options: 1,
spanId: '00f067aa0ba902b7',
traceId: '4bf92f3577b34da6a3ce929d0e0e4736',
traceState: undefined,
});
});
it('should return null when header is not available', () => {
assert.deepStrictEqual(
shimPropagation.extract(dummyGetterWithoutHeader),
null
);
});
});

describe('inject', () => {
it('should inject when span context is provided', () => {
const setHeaderFake = sinon.fake<[string, string]>();
const headerSetter: oc.HeaderSetter = {
setHeader: setHeaderFake,
};
shimPropagation.inject(headerSetter, {
options: 1,
spanId: '00f067aa0ba902b7',
traceId: '4bf92f3577b34da6a3ce929d0e0e4736',
traceState: undefined,
});
sinon.assert.calledWith(
setHeaderFake,
'traceparent',
'00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01'
);
});
});
});
});
Loading

0 comments on commit ad655a9

Please sign in to comment.