Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: browser support for exporter-trace-otlp-proto #3208

Merged
merged 51 commits into from
Jan 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
915ce52
add node & browser platform for exporter-trace-otlp-proto
pkanal Aug 24, 2022
87327f0
add browser support for proto base exporter
pkanal Aug 25, 2022
b7c8c19
add base browser class with xhr support
pkanal Aug 25, 2022
1fec3b3
add browser class for proto trace exporter
pkanal Aug 25, 2022
4214129
slight tweaks to make it work
pkanal Aug 25, 2022
d33f9bb
send data as blob to avoid making sync xhr requests
pkanal Aug 26, 2022
3dd4e17
fix lint
pkanal Oct 3, 2022
35c193f
remove console.logs and add browser proto example
pkanal Oct 3, 2022
5ed212d
cleanup and start adding tests
pkanal Oct 12, 2022
933d37e
Merge branch 'main' of github.com:pkanal/opentelemetry-js into proto-…
scheler Nov 7, 2022
9953561
Undo formatting changes
scheler Nov 7, 2022
5e87c85
exporter-trace-otlp-proto: fix compile errors
scheler Nov 8, 2022
1616d2b
Misc updates from review comments
scheler Nov 9, 2022
e3043b0
Merge branch 'main' of github.com:pkanal/opentelemetry-js into proto-…
scheler Nov 10, 2022
0020c98
Adding changelog entry
scheler Nov 10, 2022
6125ec2
Merge branch 'open-telemetry:main' into proto-exporter-browser
scheler Nov 10, 2022
c420fd0
Reverting format changes not needed
scheler Nov 12, 2022
f260db8
Merge branch 'main' into proto-exporter-browser
legendecas Nov 15, 2022
fb6cfd2
Merge branch 'open-telemetry:main' into proto-exporter-browser
scheler Nov 16, 2022
3d9ae04
Moving the send function into the class for browser case.
scheler Nov 29, 2022
46b665a
Merge branch 'main' into proto-exporter-browser
scheler Nov 30, 2022
2000c41
Adjust indentation to fix lint errors
scheler Nov 30, 2022
6366e4b
Remove template parameter that's not needed
scheler Nov 30, 2022
50e1af0
Apply review changes
scheler Dec 4, 2022
302e09c
Merge branch 'main' into proto-exporter-browser
scheler Dec 4, 2022
a16fcf5
fix the import path
scheler Dec 5, 2022
266d293
Addressing lint errors
scheler Dec 5, 2022
4cd39c0
Merge branch 'main' into proto-exporter-browser
scheler Dec 6, 2022
ed1835e
Merge branch 'open-telemetry:main' into proto-exporter-browser
scheler Dec 10, 2022
84be752
Explicit imports for browser case
scheler Dec 12, 2022
d92f5fe
More explicit exports
scheler Dec 13, 2022
61c7be7
Add missing exports
scheler Dec 13, 2022
3eed4bb
Address lint issues with export statements
scheler Dec 14, 2022
c618265
Adding missing exports
scheler Dec 14, 2022
cbabbf1
Adding missing export
scheler Dec 14, 2022
519fa7c
Using import from top level folder
scheler Dec 14, 2022
5f67e56
Merge branch 'open-telemetry:main' into proto-exporter-browser
scheler Dec 28, 2022
ad2aa0e
Trigger Build
scheler Dec 28, 2022
e57f0f2
Merge branch 'proto-exporter-browser' of github.com:pkanal/openteleme…
scheler Dec 28, 2022
b26fd7f
Merge branch 'main' into proto-exporter-browser
pichlermarc Jan 2, 2023
f421989
Update experimental/packages/exporter-trace-otlp-proto/test/browser/C…
scheler Jan 2, 2023
8064d5b
Remove trailing comma
scheler Jan 2, 2023
2678ff3
Remove blank line to fix lint error
scheler Jan 2, 2023
c898ea2
Fixes based on testing opentelemetry-web/fetch-proto
scheler Jan 6, 2023
d48503a
Add additional missing export
scheler Jan 12, 2023
a800550
Skip hex conversion of traceId for the protobuf
scheler Jan 12, 2023
598bc56
Add esm/esnext builds for the proto packages
scheler Jan 12, 2023
5596d13
Merge branch 'main' into proto-exporter-browser
scheler Jan 13, 2023
1788269
Merge branch 'main' into proto-exporter-browser
legendecas Jan 17, 2023
2e0c4ec
Merge branch 'main' into proto-exporter-browser
scheler Jan 19, 2023
9429864
Trigger Build
scheler Jan 19, 2023
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
### :rocket: (Enhancement)

* feat(instrumentation-grpc): set net.peer.name and net.peer.port on client spans [#3430](https://github.com/open-telemetry/opentelemetry-js/pull/3430)
* feat(exporter-trace-otlp-proto): Add protobuf otlp trace exporter support for browser [#3208](https://github.com/open-telemetry/opentelemetry-js/pull/3208) @pkanal

### :bug: (Bug Fix)

Expand Down
20 changes: 20 additions & 0 deletions examples/opentelemetry-web/examples/fetch-proto/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<title>Fetch Plugin Example</title>
<base href="/">

<meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
Example of using Web Tracer with Fetch plugin with console exporter and proto exporter
<script type="text/javascript" src="fetch-proto.js"></script>
<br/>
<button id="button1">Test</button>

</body>

</html>
80 changes: 80 additions & 0 deletions examples/opentelemetry-web/examples/fetch-proto/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const { context, trace } = require("@opentelemetry/api");
const { ConsoleSpanExporter, SimpleSpanProcessor} = require("@opentelemetry/sdk-trace-base");
const { WebTracerProvider } = require("@opentelemetry/sdk-trace-web");
const { FetchInstrumentation } = require("@opentelemetry/instrumentation-fetch");
const { ZoneContextManager } = require("@opentelemetry/context-zone");
const { B3Propagator } = require("@opentelemetry/propagator-b3");
const { registerInstrumentations } = require("@opentelemetry/instrumentation");
const { OTLPTraceExporter: OTLPTraceExporterProto } = require("@opentelemetry/exporter-trace-otlp-proto");

const provider = new WebTracerProvider();

// Note: For production consider using the "BatchSpanProcessor" to reduce the number of requests
// to your exporter. Using the SimpleSpanProcessor here as it sends the spans immediately to the
// exporter without delay
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
provider.addSpanProcessor(
new SimpleSpanProcessor(new OTLPTraceExporterProto())
);

provider.register({
contextManager: new ZoneContextManager(),
propagator: new B3Propagator(),
});

registerInstrumentations({
instrumentations: [
new FetchInstrumentation({
ignoreUrls: [/localhost:8090\/sockjs-node/],
propagateTraceHeaderCorsUrls: [
"https://cors-test.appspot.com/test",
"https://httpbin.org/get",
],
clearTimingResources: true,
}),
],
});

const webTracerWithZone = provider.getTracer("example-tracer-web");

const getData = (url) =>
fetch(url, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});

// example of keeping track of context between async operations
const prepareClickEvent = () => {
const url = "https://httpbin.org/get";

const element = document.getElementById("button1");

const onClick = () => {
const singleSpan = webTracerWithZone.startSpan("files-series-info");
context.with(trace.setSpan(context.active(), singleSpan), () => {
getData(url).then((_data) => {
trace
.getSpan(context.active())
.addEvent("fetching-single-span-completed");
singleSpan.end();
});
});
for (let i = 0, j = 5; i < j; i += 1) {
const span = webTracerWithZone.startSpan(`files-series-info-${i}`);
context.with(trace.setSpan(context.active(), span), () => {
getData(url).then((_data) => {
trace
.getSpan(context.active())
.addEvent(`fetching-span-${i}-completed`);
span.end();
});
});
}
};
element.addEventListener("click", onClick);
};

window.addEventListener("load", prepareClickEvent);
1 change: 1 addition & 0 deletions examples/opentelemetry-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@opentelemetry/core": "1.9.0",
"@opentelemetry/exporter-metrics-otlp-http": "0.35.0",
"@opentelemetry/exporter-trace-otlp-http": "0.35.0",
"@opentelemetry/exporter-trace-otlp-proto": "0.35.0",
"@opentelemetry/exporter-zipkin": "1.9.0",
"@opentelemetry/instrumentation": "0.35.0",
"@opentelemetry/instrumentation-fetch": "0.35.0",
Expand Down
3 changes: 2 additions & 1 deletion examples/opentelemetry-web/webpack.dev.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const common = {
'xml-http-request': 'examples/xml-http-request/index.js',
fetchXhr: 'examples/fetchXhr/index.js',
fetchXhrB3: 'examples/fetchXhrB3/index.js',
'fetch-proto': 'examples/fetch-proto/index.js',
zipkin: 'examples/zipkin/index.js',
},
output: {
Expand Down Expand Up @@ -41,7 +42,7 @@ const common = {
resolve: {
modules: [
path.resolve(directory),
'node_modules',
'node_modules'
],
extensions: ['.ts', '.js', '.jsx', '.json'],
},
Expand Down
1 change: 1 addition & 0 deletions examples/opentelemetry-web/webpack.prod.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const common = {
'xml-http-request': 'examples/xml-http-request/index.js',
fetchXhr: 'examples/fetchXhr/index.js',
fetchXhrB3: 'examples/fetchXhrB3/index.js',
"fetch-proto": "examples/fetch-proto/index.js",
zipkin: 'examples/zipkin/index.js',
},
output: {
Expand Down
26 changes: 26 additions & 0 deletions experimental/packages/exporter-trace-otlp-proto/karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*!
* 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
*
* http://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.
*/

const karmaWebpackConfig = require('../../../karma.webpack');
const karmaBaseConfig = require('../../../karma.base');

module.exports = (config) => {
config.set(Object.assign({}, karmaBaseConfig, {
webpack: karmaWebpackConfig,
files: ['test/browser/index-webpack.ts'],
preprocessors: { 'test/browser/index-webpack.ts': ['webpack'] }
}))
};
23 changes: 19 additions & 4 deletions experimental/packages/exporter-trace-otlp-proto/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@
"version": "0.35.0",
"description": "OpenTelemetry Collector Exporter allows user to send collected traces to the OpenTelemetry Collector using protobuf over HTTP",
"main": "build/src/index.js",
pichlermarc marked this conversation as resolved.
Show resolved Hide resolved
"module": "build/esm/index.js",
"esnext": "build/esnext/index.js",
"types": "build/src/index.d.ts",
"repository": "open-telemetry/opentelemetry-js",
"browser": {
"./src/platform/index.ts": "./src/platform/browser/index.ts",
"./build/esm/platform/index.js": "./build/esm/platform/browser/index.js",
"./build/esnext/platform/index.js": "./build/esnext/platform/browser/index.js",
"./build/src/platform/index.js": "./build/src/platform/browser/index.js"
},
"scripts": {
"prepublishOnly": "npm run compile",
"compile": "tsc --build",
"clean": "tsc --build --clean",
"compile": "tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json",
"clean": "tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"tdd": "npm run test -- --watch-extensions ts --watch",
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'",
"test:browser": "nyc karma start --single-run",
"version": "node ../../../scripts/version-update.js",
"watch": "tsc --build --watch",
"watch": "tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json",
"precompile": "lerna run version --scope $(npm pkg get name) --include-dependencies",
"prewatch": "npm run precompile",
"peer-api-check": "node ../../../scripts/peer-api-check.js",
Expand All @@ -35,6 +44,12 @@
"node": ">=14"
},
"files": [
"build/esm/**/*.js",
"build/esm/**/*.js.map",
"build/esm/**/*.d.ts",
"build/esnext/**/*.js",
"build/esnext/**/*.js.map",
"build/esnext/**/*.d.ts",
"build/src/**/*.js",
"build/src/**/*.js.map",
"build/src/**/*.d.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export * from './OTLPTraceExporter';
export { OTLPTraceExporter } from './platform';
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 { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';
import { getEnv, baggageUtils } from '@opentelemetry/core';
import {
OTLPExporterConfigBase,
appendResourcePathToUrl,
appendRootPathToUrlIfNeeded,
} from '@opentelemetry/otlp-exporter-base';
import {
OTLPProtoExporterBrowserBase,
ServiceClientType,
} from '@opentelemetry/otlp-proto-exporter-base';
import {
createExportTraceServiceRequest,
IExportTraceServiceRequest,
} from '@opentelemetry/otlp-transformer';

const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/traces';
const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;

/**
* Collector Trace Exporter for Web
*/
export class OTLPTraceExporter
extends OTLPProtoExporterBrowserBase<ReadableSpan, IExportTraceServiceRequest>
implements SpanExporter
{
constructor(config: OTLPExporterConfigBase = {}) {
super(config);
this._headers = Object.assign(
this._headers,
baggageUtils.parseKeyPairsIntoRecord(
getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS
)
);
}
convert(spans: ReadableSpan[]): IExportTraceServiceRequest {
return createExportTraceServiceRequest(spans);
}

getDefaultUrl(config: OTLPExporterConfigBase): string {
return typeof config.url === 'string'
Copy link
Contributor

@MSNev MSNev Dec 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion
This is a little more readable, performant (and minifiable) by rewriting as

let endpoint = config.url;
if (!endpoint || endpoint !== 'string') {
    let env = getEnv();
    let tracesEndpoint = env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;
    if (tracesEndpoint) {
        endpoint = appendRootPathToUrlIfNeeded(tracesEndpoint);
    } else {
        let otlpEndpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;
        if (otlpEndpoint) {
            endpoint = appendResourcePathToUrl(otlpEndpoint, DEFAULT_COLLECTOR_RESOURCE_PATH);
        }
    }
}

return endpoint || DEFAULT_COLLECTOR_URL;

As well as less error prone for someone coming looking at this after you

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MSNev The function getDefaultUrl is written this way in multiple packages. I suggest we take this up in a separate PR since it's unrelated to this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we raise an issue for this then, otherwise it will not get done. This can include the suggestion I have above as the implementation.

? config.url
: getEnv().OTEL_EXPORTER_OTLP_TRACES_ENDPOINT.length > 0
? appendRootPathToUrlIfNeeded(getEnv().OTEL_EXPORTER_OTLP_TRACES_ENDPOINT)
: getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
? appendResourcePathToUrl(
getEnv().OTEL_EXPORTER_OTLP_ENDPOINT,
DEFAULT_COLLECTOR_RESOURCE_PATH
)
: DEFAULT_COLLECTOR_URL;
}

getServiceClientType() {
return ServiceClientType.SPANS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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.
*/
export { OTLPTraceExporter } from './OTLPTraceExporter';
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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.
*/
export { OTLPTraceExporter } from './node';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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.
*/

export { OTLPTraceExporter } from './OTLPTraceExporter';
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 assert from 'assert';
import * as sinon from 'sinon';
import { OTLPTraceExporter } from '../../src/platform/browser/index';

describe('OTLPTraceExporter - web', () => {
let collectorTraceExporter: OTLPTraceExporter;
describe('constructor', () => {
let onInitSpy: any;
beforeEach(() => {
onInitSpy = sinon.stub(OTLPTraceExporter.prototype, 'onInit');
const collectorExporterConfig = {
hostname: 'foo',
url: 'http://foo.bar.com',
};
collectorTraceExporter = new OTLPTraceExporter(collectorExporterConfig);
});
afterEach(() => {
sinon.restore();
});
it('should create an instance', () => {
assert.ok(typeof collectorTraceExporter !== 'undefined');
});
it('should call onInit', () => {
assert.strictEqual(onInitSpy.callCount, 1);
});
it('should set hostname', () => {
assert.strictEqual(collectorTraceExporter.hostname, 'foo');
});

it('should set url', () => {
assert.strictEqual(collectorTraceExporter.url, 'http://foo.bar.com');
});
});
});
Loading