diff --git a/.github/workflows/label-releases.yml b/.github/workflows/label-releases.yml
new file mode 100644
index 0000000000..29c5357f71
--- /dev/null
+++ b/.github/workflows/label-releases.yml
@@ -0,0 +1,12 @@
+on:
+ pull_request_target:
+ branches:
+ - main
+
+jobs:
+ label-release:
+ if: ${{ startsWith(github.event.pull_request.title, 'release:') }}
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo this is a release PR
+ - run: gh pr edit ${{ github.event.pull_request.number }} --add-label release
diff --git a/.github/workflows/peer-api.yml b/.github/workflows/peer-api.yml
index ac90efe981..e6f52cccd7 100644
--- a/.github/workflows/peer-api.yml
+++ b/.github/workflows/peer-api.yml
@@ -11,7 +11,7 @@ jobs:
peer-api-check:
runs-on: ubuntu-latest
container:
- image: node:18
+ image: node:20
steps:
- name: Checkout
uses: actions/checkout@v3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07bd03fa7a..f827e31585 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,17 +11,25 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
### :rocket: (Enhancement)
-* feat(core): add environment variables for OTLP log exporters. [#3712](https://github.com/open-telemetry/opentelemetry-js/pull/3712/) @llc1123
+* feat(SpanExpoter): Add optional forceFlush to SpanExporter interface [#3753](https://github.com/open-telemetry/opentelemetry-js/pull/3753/) @sgracias1 @JacksonWeber
### :bug: (Bug Fix)
-* fix(http-instrumentation): stop listening to `request`'s `close` event once it has emitted `response` [#3625](https://github.com/open-telemetry/opentelemetry-js/pull/3625) @SimenB
-* fix(sdk-node): fix initialization in bundled environments by not loading @opentelemetry/exporter-jaeger [#3739](https://github.com/open-telemetry/opentelemetry-js/pull/3739) @pichlermarc
-
### :books: (Refine Doc)
### :house: (Internal)
+## 1.13.0
+
+### :rocket: (Enhancement)
+
+* feat(core): add environment variables for OTLP log exporters. [#3712](https://github.com/open-telemetry/opentelemetry-js/pull/3712/) @llc1123
+
+### :bug: (Bug Fix)
+
+* fix(http-instrumentation): stop listening to `request`'s `close` event once it has emitted `response` [#3625](https://github.com/open-telemetry/opentelemetry-js/pull/3625) @SimenB
+* fix(sdk-node): fix initialization in bundled environments by not loading @opentelemetry/exporter-jaeger [#3739](https://github.com/open-telemetry/opentelemetry-js/pull/3739) @pichlermarc
+
## 1.12.0
### :rocket: (Enhancement)
diff --git a/README.md b/README.md
index 9daf9d7385..ca72796747 100644
--- a/README.md
+++ b/README.md
@@ -188,6 +188,8 @@ We have a weekly SIG meeting! See the [community page](https://github.com/open-t
- [Gerhard Stöbich](https://github.com/Flarna), Dynatrace
- [Haddas Bronfman](https://github.com/haddasbronfman), Cisco
+- [Hector Hernandez](https://github.com/hectorhdzg), Microsoft
+- [Jamie Danielson](https://github.com/JamieDanielson), Honeycomb
- [John Bley](https://github.com/johnbley), Splunk
- [Mark Wolff](https://github.com/markwolff), Microsoft
- [Martin Kuba](https://github.com/martinkuba), Lightstep
@@ -195,6 +197,7 @@ We have a weekly SIG meeting! See the [community page](https://github.com/open-t
- [Naseem K. Ullah](https://github.com/naseemkullah), Transit
- [Neville Wylie](https://github.com/MSNev), Microsoft
- [Olivier Albertini](https://github.com/OlivierAlbertini), Ville de Montréal
+- [Purvi Kanal](https://github.com/pkanal), Honeycomb
- [Svetlana Brennan](https://github.com/svetlanabrennan), New Relic
*Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/main/community-membership.md#approver).*
diff --git a/examples/README.md b/examples/README.md
index c594e5f442..dcef5e8d8e 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -17,6 +17,7 @@ use the latest and greatest features, and best practices.
| [grpc](grpc/) | gRPC Instrumentation to automatically collect trace data and export them to the backend of choice | Intermediate |
| [otlp-exporter-node](otlp-exporter-node/) | This example shows how to use `@opentelemetry/exporter-otlp-http` to instrument a simple Node.js application | Intermediate |
| [opentracing-shim](opentracing-shim/) | This is a simple example that demonstrates how existing OpenTracing instrumentation can be integrated with OpenTelemetry | Intermediate |
+| [esm-http-ts](esm-http-ts/) | This is a simple example that demonstrates tracing HTTP request, with an app written in TypeScript and transpiled to ES Modules. | Intermediate |
Examples of experimental packages can be found at [experimental/examples](../experimental/examples).
diff --git a/examples/esm-http-ts/README.md b/examples/esm-http-ts/README.md
new file mode 100644
index 0000000000..72f0e2dbf4
--- /dev/null
+++ b/examples/esm-http-ts/README.md
@@ -0,0 +1,25 @@
+# Overview
+
+This is a simple example that demonstrates tracing HTTP request, with an app written in TypeScript and transpiled to ES Modules.
+
+## Installation
+
+```sh
+# from this directory
+npm install
+npm run build
+npm start
+```
+
+In a separate terminal, `curl localhost:3000`.
+
+See two spans in the console (one manual, one for http instrumentation)
+
+## Useful links
+
+- For more information on OpenTelemetry, visit:
+- For more information on OpenTelemetry for Node.js, visit:
+
+## LICENSE
+
+Apache License 2.0
diff --git a/examples/esm-http-ts/index.ts b/examples/esm-http-ts/index.ts
new file mode 100644
index 0000000000..b4719a8bc7
--- /dev/null
+++ b/examples/esm-http-ts/index.ts
@@ -0,0 +1,43 @@
+import { registerInstrumentations } from '@opentelemetry/instrumentation';
+import { trace, DiagConsoleLogger, DiagLogLevel, diag } from '@opentelemetry/api';
+import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
+import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
+import {
+ ConsoleSpanExporter,
+ SimpleSpanProcessor,
+} from '@opentelemetry/sdk-trace-base';
+import { Resource } from '@opentelemetry/resources';
+import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
+import http from 'http';
+
+diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);
+const tracerProvider = new NodeTracerProvider({
+ resource: new Resource({
+ [SemanticResourceAttributes.SERVICE_NAME]: 'esm-http-ts-example',
+ }),
+});
+const exporter = new ConsoleSpanExporter();
+const processor = new SimpleSpanProcessor(exporter);
+tracerProvider.addSpanProcessor(processor);
+tracerProvider.register();
+
+registerInstrumentations({
+ instrumentations: [new HttpInstrumentation()],
+});
+
+const hostname = '0.0.0.0';
+const port = 3000;
+
+const server = http.createServer((req, res) => {
+ res.statusCode = 200;
+ res.setHeader('Content-Type', 'text/plain');
+ const tracer = trace.getTracer('esm-tracer');
+ tracer.startActiveSpan('manual', span => {
+ span.end();
+ });
+ res.end('Hello, World!\n');
+});
+
+server.listen(port, hostname, () => {
+ console.log(`Server running at http://${hostname}:${port}/`);
+});
diff --git a/examples/esm-http-ts/package.json b/examples/esm-http-ts/package.json
new file mode 100644
index 0000000000..49c0e2601f
--- /dev/null
+++ b/examples/esm-http-ts/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "esm-http-ts",
+ "private": true,
+ "version": "0.38.0",
+ "description": "Example of HTTP integration with OpenTelemetry using ESM and TypeScript",
+ "main": "build/index.js",
+ "type": "module",
+ "scripts": {
+ "build": "tsc --build",
+ "start": "node --experimental-loader=@opentelemetry/instrumentation/hook.mjs ./build/index.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/open-telemetry/opentelemetry-js.git"
+ },
+ "keywords": [
+ "opentelemetry",
+ "http",
+ "tracing",
+ "esm",
+ "typescript"
+ ],
+ "engines": {
+ "node": ">=14"
+ },
+ "author": "OpenTelemetry Authors",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/open-telemetry/opentelemetry-js/issues"
+ },
+ "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/",
+ "dependencies": {
+ "@opentelemetry/api": "1.4.0",
+ "@opentelemetry/exporter-trace-otlp-proto": "0.38.0",
+ "@opentelemetry/instrumentation": "0.38.0",
+ "@opentelemetry/instrumentation-http": "0.38.0",
+ "@opentelemetry/resources": "1.9.1",
+ "@opentelemetry/sdk-trace-base": "1.9.1",
+ "@opentelemetry/sdk-trace-node": "1.9.1",
+ "@opentelemetry/semantic-conventions": "1.9.1"
+ }
+}
diff --git a/examples/esm-http-ts/tsconfig.json b/examples/esm-http-ts/tsconfig.json
new file mode 100644
index 0000000000..5f821d66c7
--- /dev/null
+++ b/examples/esm-http-ts/tsconfig.json
@@ -0,0 +1,25 @@
+{
+ "compilerOptions": {
+ /* Language and Environment */
+ "target": "ES2020" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+
+ /* Modules */
+ "module": "ESNext" /* Specify what module code is generated. */,
+ "rootDir": "." /* Specify the root folder within your source files. */,
+ "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
+ "resolveJsonModule": true /* Enable importing .json files. */,
+
+ /* Emit */
+ "outDir": "build" /* Specify an output folder for all emitted files. */,
+
+ /* Interop Constraints */
+ "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */,
+ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
+
+ /* Completeness */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ },
+ "include": ["**/*.ts", "**/*.js", "*.config.js"],
+ "exclude": ["node_modules"]
+}
diff --git a/examples/http/package.json b/examples/http/package.json
index 50ea5401f1..e06dd1af2f 100644
--- a/examples/http/package.json
+++ b/examples/http/package.json
@@ -1,7 +1,7 @@
{
"name": "http-example",
"private": true,
- "version": "0.37.0",
+ "version": "0.39.1",
"description": "Example of HTTP integration with OpenTelemetry",
"main": "index.js",
"scripts": {
@@ -29,14 +29,14 @@
},
"dependencies": {
"@opentelemetry/api": "^1.3.0",
- "@opentelemetry/exporter-jaeger": "1.9.1",
- "@opentelemetry/exporter-zipkin": "1.9.1",
- "@opentelemetry/instrumentation": "0.35.1",
- "@opentelemetry/instrumentation-http": "0.35.1",
- "@opentelemetry/resources": "1.9.1",
- "@opentelemetry/sdk-trace-base": "1.9.1",
- "@opentelemetry/sdk-trace-node": "1.9.1",
- "@opentelemetry/semantic-conventions": "1.9.1"
+ "@opentelemetry/exporter-jaeger": "1.13.0",
+ "@opentelemetry/exporter-zipkin": "1.13.0",
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/instrumentation-http": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/sdk-trace-node": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/http",
"devDependencies": {
diff --git a/examples/https/package.json b/examples/https/package.json
index b13422bea9..62b65273f2 100644
--- a/examples/https/package.json
+++ b/examples/https/package.json
@@ -1,7 +1,7 @@
{
"name": "https-example",
"private": true,
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "Example of HTTPs integration with OpenTelemetry",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -33,14 +33,14 @@
},
"dependencies": {
"@opentelemetry/api": "^1.0.0",
- "@opentelemetry/exporter-jaeger": "1.12.0",
- "@opentelemetry/exporter-zipkin": "1.12.0",
- "@opentelemetry/instrumentation": "0.38.0",
- "@opentelemetry/instrumentation-http": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
- "@opentelemetry/sdk-trace-node": "1.12.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/exporter-jaeger": "1.13.0",
+ "@opentelemetry/exporter-zipkin": "1.13.0",
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/instrumentation-http": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/sdk-trace-node": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/https",
"devDependencies": {
diff --git a/examples/opentelemetry-web/package.json b/examples/opentelemetry-web/package.json
index 105d86b649..c4c75e460c 100644
--- a/examples/opentelemetry-web/package.json
+++ b/examples/opentelemetry-web/package.json
@@ -1,7 +1,7 @@
{
"name": "web-opentelemetry-example",
"private": true,
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "Example of using @opentelemetry/sdk-trace-web and @opentelemetry/sdk-metrics in browser",
"main": "index.js",
"scripts": {
@@ -43,20 +43,20 @@
},
"dependencies": {
"@opentelemetry/api": "^1.3.0",
- "@opentelemetry/context-zone": "1.12.0",
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/exporter-metrics-otlp-http": "0.38.0",
- "@opentelemetry/exporter-trace-otlp-http": "0.38.0",
- "@opentelemetry/exporter-trace-otlp-proto": "0.38.0",
- "@opentelemetry/exporter-zipkin": "1.12.0",
- "@opentelemetry/instrumentation": "0.38.0",
- "@opentelemetry/instrumentation-fetch": "0.38.0",
- "@opentelemetry/instrumentation-xml-http-request": "0.38.0",
- "@opentelemetry/propagator-b3": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
- "@opentelemetry/sdk-trace-web": "1.12.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/context-zone": "1.13.0",
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/exporter-metrics-otlp-http": "0.39.1",
+ "@opentelemetry/exporter-trace-otlp-http": "0.39.1",
+ "@opentelemetry/exporter-trace-otlp-proto": "0.39.1",
+ "@opentelemetry/exporter-zipkin": "1.13.0",
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/instrumentation-fetch": "0.39.1",
+ "@opentelemetry/instrumentation-xml-http-request": "0.39.1",
+ "@opentelemetry/propagator-b3": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/sdk-trace-web": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/tracer-web"
}
diff --git a/examples/otlp-exporter-node/package.json b/examples/otlp-exporter-node/package.json
index e5e6b21974..c19ae9ea59 100644
--- a/examples/otlp-exporter-node/package.json
+++ b/examples/otlp-exporter-node/package.json
@@ -1,7 +1,7 @@
{
"name": "example-otlp-exporter-node",
"private": true,
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "Example of using @opentelemetry/collector-exporter in Node.js",
"main": "index.js",
"scripts": {
@@ -29,17 +29,17 @@
},
"dependencies": {
"@opentelemetry/api": "^1.3.0",
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/exporter-metrics-otlp-grpc": "0.38.0",
- "@opentelemetry/exporter-metrics-otlp-http": "0.38.0",
- "@opentelemetry/exporter-metrics-otlp-proto": "0.38.0",
- "@opentelemetry/exporter-trace-otlp-grpc": "0.38.0",
- "@opentelemetry/exporter-trace-otlp-http": "0.38.0",
- "@opentelemetry/exporter-trace-otlp-proto": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/exporter-metrics-otlp-grpc": "0.39.1",
+ "@opentelemetry/exporter-metrics-otlp-http": "0.39.1",
+ "@opentelemetry/exporter-metrics-otlp-proto": "0.39.1",
+ "@opentelemetry/exporter-trace-otlp-grpc": "0.39.1",
+ "@opentelemetry/exporter-trace-otlp-http": "0.39.1",
+ "@opentelemetry/exporter-trace-otlp-proto": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/otlp-exporter-node"
}
diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md
index 6d98dd5c31..b109e6f0d0 100644
--- a/experimental/CHANGELOG.md
+++ b/experimental/CHANGELOG.md
@@ -6,6 +6,39 @@ All notable changes to experimental packages in this project will be documented
### :boom: Breaking Change
+* fix(exporter-logs-otlp-grpc): change OTLPLogsExporter to OTLPLogExporter [#3819](https://github.com/open-telemetry/opentelemetry-js/pull/3819) @fuaiyi
+* chore(instrumentation-grpc): add 'grpc' deprecation notice postinstall script [#3833](https://github.com/open-telemetry/opentelemetry-js/pull/3833) @pichlermarc
+ * Support for telemetry generation for the [`grpc`](https://www.npmjs.com/package/grpc) module will be dropped in the next release as the package has been
+ deprecated for over 1 year, please migrate to [`@grpc/grpc-js`](https://www.npmjs.com/package/@grpc/grpc-js) to continue receiving telemetry.
+
+### :rocket: (Enhancement)
+
+* feat(api-logs): support map in log attributes. [#3821](https://github.com/open-telemetry/opentelemetry-js/pull/3821) @Abinet18
+* feat(instrumentation): add ESM support for instrumentation. [#3698](https://github.com/open-telemetry/opentelemetry-js/pull/3698) @JamieDanielson, @pkanal, @vmarchaud, @lizthegrey, @bengl
+* feat(exporter-logs-otlp-http): otlp-http exporter for logs. [#3764](https://github.com/open-telemetry/opentelemetry-js/pull/3764/) @fuaiyi
+* feat(otlp-trace-exporters): Add User-Agent header to OTLP trace exporters. [#3790](https://github.com/open-telemetry/opentelemetry-js/pull/3790) @JamieDanielson
+* feat(otlp-metric-exporters): Add User-Agent header to OTLP metric exporters. [#3806](https://github.com/open-telemetry/opentelemetry-js/pull/3806) @JamieDanielson
+* feat(opencensus-shim): add OpenCensus trace shim [#3809](https://github.com/open-telemetry/opentelemetry-js/pull/3809) @aabmass
+* feat(exporter-logs-otlp-proto): protobuf exporter for logs. [#3779](https://github.com/open-telemetry/opentelemetry-js/pull/3779) @Abinet18
+* feat(otlp-exporter-base): Add fetch sender for WebWorker and ServiceWorker environment. [#3542](https://github.com/open-telemetry/opentelemetry-js/pull/3542) @sugi
+
+### :bug: (Bug Fix)
+
+* fix(sdk-node): use resource interface instead of concrete class [#3803](https://github.com/open-telemetry/opentelemetry-js/pull/3803) @blumamir
+* fix(sdk-logs): remove includeTraceContext configuration and use LogRecord context when available [#3817](https://github.com/open-telemetry/opentelemetry-js/pull/3817) @hectorhdzg
+
+### :books: (Refine Doc)
+
+### :house: (Internal)
+
+## 0.39.1
+
+### :bug: (Bug Fix)
+
+* fix(otlp-transformer): move api-logs to dependencies [#3798](https://github.com/open-telemetry/opentelemetry-js/pull/3798) @pichlermarc
+
+## 0.39.0
+
### :rocket: (Enhancement)
* feat(otlp-transformer): support log records. [#3712](https://github.com/open-telemetry/opentelemetry-js/pull/3712/) @llc1123
@@ -13,7 +46,7 @@ All notable changes to experimental packages in this project will be documented
* feat(exporter-logs-otlp-grpc): otlp-grpc exporter for logs. [#3712](https://github.com/open-telemetry/opentelemetry-js/pull/3712/) @llc1123
* feat(otlp-grpc-exporter-base): use statically generated protobuf code [#3705](https://github.com/open-telemetry/opentelemetry-js/pull/3705) @pichlermarc
* refactor(otlp-transformer): refine metric transformers. [#3770](https://github.com/open-telemetry/opentelemetry-js/pull/3770/) @llc1123
-* feat(otlp-exporter-base): Add fetch sender for WebWorker and ServiceWorker environment. [#3542](https://github.com/open-telemetry/opentelemetry-js/pull/3542) @sugi
+* feat(api-logs): add `ObservedTimestamp` to `LogRecord`. [#3787](https://github.com/open-telemetry/opentelemetry-js/pull/3787/) @llc1123
### :bug: (Bug Fix)
diff --git a/experimental/backwards-compatability/node14/package.json b/experimental/backwards-compatability/node14/package.json
index 6b8f162584..fb30bd3215 100644
--- a/experimental/backwards-compatability/node14/package.json
+++ b/experimental/backwards-compatability/node14/package.json
@@ -1,6 +1,6 @@
{
"name": "backcompat-node14",
- "version": "0.38.0",
+ "version": "0.39.1",
"private": true,
"description": "Backwards compatability app for node 14 types and the OpenTelemetry Node.js SDK",
"main": "index.js",
@@ -9,8 +9,8 @@
"peer-api-check": "node ../../../scripts/peer-api-check.js"
},
"dependencies": {
- "@opentelemetry/sdk-node": "0.38.0",
- "@opentelemetry/sdk-trace-base": "1.12.0"
+ "@opentelemetry/sdk-node": "0.39.1",
+ "@opentelemetry/sdk-trace-base": "1.13.0"
},
"devDependencies": {
"@types/node": "14.18.25",
diff --git a/experimental/backwards-compatability/node16/package.json b/experimental/backwards-compatability/node16/package.json
index 67caa211af..bf74118063 100644
--- a/experimental/backwards-compatability/node16/package.json
+++ b/experimental/backwards-compatability/node16/package.json
@@ -1,6 +1,6 @@
{
"name": "backcompat-node16",
- "version": "0.38.0",
+ "version": "0.39.1",
"private": true,
"description": "Backwards compatability app for node 16 types and the OpenTelemetry Node.js SDK",
"main": "index.js",
@@ -9,8 +9,8 @@
"peer-api-check": "node ../../../scripts/peer-api-check.js"
},
"dependencies": {
- "@opentelemetry/sdk-node": "0.38.0",
- "@opentelemetry/sdk-trace-base": "1.12.0"
+ "@opentelemetry/sdk-node": "0.39.1",
+ "@opentelemetry/sdk-trace-base": "1.13.0"
},
"devDependencies": {
"@types/node": "16.11.52",
diff --git a/experimental/examples/logs/package.json b/experimental/examples/logs/package.json
index a857e59f11..3e10700d19 100644
--- a/experimental/examples/logs/package.json
+++ b/experimental/examples/logs/package.json
@@ -1,17 +1,17 @@
{
"name": "logs-example",
- "version": "0.1.0",
+ "version": "0.2.0",
"private": true,
"scripts": {
"start": "ts-node index.ts"
},
"dependencies": {
"@opentelemetry/api": "^1.4.1",
- "@opentelemetry/api-logs": "^0.38.0",
- "@opentelemetry/sdk-logs": "^0.38.0"
+ "@opentelemetry/api-logs": "0.39.1",
+ "@opentelemetry/sdk-logs": "0.39.1"
},
"devDependencies": {
- "ts-node": "^10.9.1",
- "@types/node": "18.6.5"
+ "@types/node": "18.6.5",
+ "ts-node": "^10.9.1"
}
}
diff --git a/experimental/examples/prometheus/package.json b/experimental/examples/prometheus/package.json
index 404a13af6f..d1c5cb9ce6 100644
--- a/experimental/examples/prometheus/package.json
+++ b/experimental/examples/prometheus/package.json
@@ -1,6 +1,6 @@
{
"name": "prometheus-example",
- "version": "0.38.0",
+ "version": "0.39.1",
"private": true,
"description": "Example of using @opentelemetry/sdk-metrics and @opentelemetry/exporter-prometheus",
"main": "index.js",
@@ -11,7 +11,7 @@
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/api": "^1.3.0",
- "@opentelemetry/exporter-prometheus": "0.38.0",
- "@opentelemetry/sdk-metrics": "1.12.0"
+ "@opentelemetry/exporter-prometheus": "0.39.1",
+ "@opentelemetry/sdk-metrics": "1.13.0"
}
}
diff --git a/experimental/packages/api-events/package.json b/experimental/packages/api-events/package.json
index 04b649499b..bc1a24a54b 100644
--- a/experimental/packages/api-events/package.json
+++ b/experimental/packages/api-events/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/api-events",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "Public events API for OpenTelemetry",
"main": "build/src/index.js",
"module": "build/esm/index.js",
diff --git a/experimental/packages/api-logs/package.json b/experimental/packages/api-logs/package.json
index dfb6d9ab6a..9143ef36d0 100644
--- a/experimental/packages/api-logs/package.json
+++ b/experimental/packages/api-logs/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/api-logs",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "Public logs API for OpenTelemetry",
"main": "build/src/index.js",
"module": "build/esm/index.js",
diff --git a/experimental/packages/api-logs/src/types/LogRecord.ts b/experimental/packages/api-logs/src/types/LogRecord.ts
index a2c7d25ad3..59718aa30b 100644
--- a/experimental/packages/api-logs/src/types/LogRecord.ts
+++ b/experimental/packages/api-logs/src/types/LogRecord.ts
@@ -14,7 +14,12 @@
* limitations under the License.
*/
-import { Attributes, Context } from '@opentelemetry/api';
+import { AttributeValue, Context } from '@opentelemetry/api';
+
+export type LogAttributeValue = AttributeValue | LogAttributes;
+export interface LogAttributes {
+ [attributeKey: string]: LogAttributeValue | undefined;
+}
export enum SeverityNumber {
UNSPECIFIED = 0,
@@ -50,6 +55,11 @@ export interface LogRecord {
*/
timestamp?: number;
+ /**
+ * Time when the event was observed by the collection system.
+ */
+ observedTimestamp?: number;
+
/**
* Numerical value of the severity.
*/
@@ -68,7 +78,7 @@ export interface LogRecord {
/**
* Attributes that define the log record.
*/
- attributes?: Attributes;
+ attributes?: LogAttributes;
/**
* The Context associated with the LogRecord.
diff --git a/experimental/packages/api-logs/src/types/LoggerOptions.ts b/experimental/packages/api-logs/src/types/LoggerOptions.ts
index a57d44a739..fdcedcb464 100644
--- a/experimental/packages/api-logs/src/types/LoggerOptions.ts
+++ b/experimental/packages/api-logs/src/types/LoggerOptions.ts
@@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import { Attributes } from '@opentelemetry/api';
-
export interface LoggerOptions {
/**
* The schemaUrl of the tracer or instrumentation library
diff --git a/experimental/packages/exporter-logs-otlp-grpc/README.md b/experimental/packages/exporter-logs-otlp-grpc/README.md
index dee62b496f..17c9573398 100644
--- a/experimental/packages/exporter-logs-otlp-grpc/README.md
+++ b/experimental/packages/exporter-logs-otlp-grpc/README.md
@@ -22,7 +22,7 @@ To see documentation and sample code for the metric exporter, see the [exporter-
## Logs in Node - GRPC
-The OTLPLogsExporter in Node expects the URL to only be the hostname. It will not work with `/v1/logs`. All
+The OTLPLogExporter in Node expects the URL to only be the hostname. It will not work with `/v1/logs`. All
options that work with trace also work with logs.
```js
@@ -30,14 +30,14 @@ import {
LoggerProvider,
BatchLogRecordProcessor,
} from '@opentelemetry/sdk-logs';
-import { OTLPLogsExporter } from '@opentelemetry/exporter-logs-otlp-grpc';
+import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc';
const collectorOptions = {
// url is optional and can be omitted - default is http://localhost:4317
url: 'http://:',
};
-const loggerExporter = new OTLPLogsExporter(collectorOptions);
+const loggerExporter = new OTLPLogExporter(collectorOptions);
const loggerProvider = new LoggerProvider();
loggerProvider.addLogRecordProcessor(
diff --git a/experimental/packages/exporter-logs-otlp-grpc/package.json b/experimental/packages/exporter-logs-otlp-grpc/package.json
index 661e8c7221..99cb19287e 100644
--- a/experimental/packages/exporter-logs-otlp-grpc/package.json
+++ b/experimental/packages/exporter-logs-otlp-grpc/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-logs-otlp-grpc",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Collector Exporter allows user to send collected log records to the OpenTelemetry Collector",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -51,9 +51,9 @@
"@babel/core": "7.16.0",
"@grpc/proto-loader": "^0.7.3",
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/api-logs": "0.38.0",
- "@opentelemetry/otlp-exporter-base": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
+ "@opentelemetry/api-logs": "0.39.1",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/sinon": "10.0.13",
@@ -71,11 +71,11 @@
},
"dependencies": {
"@grpc/grpc-js": "^1.7.1",
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/otlp-grpc-exporter-base": "0.38.0",
- "@opentelemetry/otlp-transformer": "0.38.0",
- "@opentelemetry/sdk-logs": "0.38.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/otlp-grpc-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/sdk-logs": "0.39.1"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/exporter-logs-otlp-grpc",
"sideEffects": false
-}
\ No newline at end of file
+}
diff --git a/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogsExporter.ts b/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts
similarity index 98%
rename from experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogsExporter.ts
rename to experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts
index e4484fdb39..675ce83db0 100644
--- a/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogsExporter.ts
+++ b/experimental/packages/exporter-logs-otlp-grpc/src/OTLPLogExporter.ts
@@ -32,7 +32,7 @@ import {
/**
* OTLP Logs Exporter for Node
*/
-export class OTLPLogsExporter
+export class OTLPLogExporter
extends OTLPGRPCExporterNodeBase
implements LogRecordExporter
{
diff --git a/experimental/packages/exporter-logs-otlp-grpc/src/index.ts b/experimental/packages/exporter-logs-otlp-grpc/src/index.ts
index b35d852d90..b071c78ef5 100644
--- a/experimental/packages/exporter-logs-otlp-grpc/src/index.ts
+++ b/experimental/packages/exporter-logs-otlp-grpc/src/index.ts
@@ -14,4 +14,4 @@
* limitations under the License.
*/
-export * from './OTLPLogsExporter';
+export * from './OTLPLogExporter';
diff --git a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogsExporter.test.ts b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts
similarity index 91%
rename from experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogsExporter.test.ts
rename to experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts
index d413b8902d..48f1fa865e 100644
--- a/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogsExporter.test.ts
+++ b/experimental/packages/exporter-logs-otlp-grpc/test/OTLPLogExporter.test.ts
@@ -22,7 +22,7 @@ import * as fs from 'fs';
import * as grpc from '@grpc/grpc-js';
import * as path from 'path';
import * as sinon from 'sinon';
-import { OTLPLogsExporter } from '../src';
+import { OTLPLogExporter } from '../src';
import {
ensureExportedLogRecordIsCorrect,
@@ -44,7 +44,7 @@ const includeDirs = [
path.resolve(__dirname, '../../otlp-grpc-exporter-base/protos'),
];
-const address = 'localhost:1501';
+const address = 'localhost:1503';
type TestParams = {
useTLS?: boolean;
@@ -55,10 +55,10 @@ const metadata = new grpc.Metadata();
metadata.set('k', 'v');
const testCollectorExporter = (params: TestParams) =>
- describe(`OTLPLogsExporter - node ${
- params.useTLS ? 'with' : 'without'
- } TLS, ${params.metadata ? 'with' : 'without'} metadata`, () => {
- let collectorExporter: OTLPLogsExporter;
+ describe(`OTLPLogExporter - node ${params.useTLS ? 'with' : 'without'} TLS, ${
+ params.metadata ? 'with' : 'without'
+ } metadata`, () => {
+ let collectorExporter: OTLPLogExporter;
let server: grpc.Server;
let exportedData: IResourceLogs | undefined;
let reqMetadata: grpc.Metadata | undefined;
@@ -122,7 +122,7 @@ const testCollectorExporter = (params: TestParams) =>
fs.readFileSync('./test/certs/client.crt')
)
: grpc.credentials.createInsecure();
- collectorExporter = new OTLPLogsExporter({
+ collectorExporter = new OTLPLogExporter({
url: 'https://' + address,
credentials,
metadata: params.metadata,
@@ -140,7 +140,7 @@ const testCollectorExporter = (params: TestParams) =>
it('should warn about headers when using grpc', () => {
// Need to stub/spy on the underlying logger as the 'diag' instance is global
const spyLoggerWarn = sinon.stub(diag, 'warn');
- collectorExporter = new OTLPLogsExporter({
+ collectorExporter = new OTLPLogExporter({
url: `http://${address}`,
headers: {
foo: 'bar',
@@ -151,7 +151,7 @@ const testCollectorExporter = (params: TestParams) =>
});
it('should warn about path in url', () => {
const spyLoggerWarn = sinon.stub(diag, 'warn');
- collectorExporter = new OTLPLogsExporter({
+ collectorExporter = new OTLPLogExporter({
url: `http://${address}/v1/logs`,
});
const args = spyLoggerWarn.args[0];
@@ -198,7 +198,7 @@ const testCollectorExporter = (params: TestParams) =>
)
: grpc.credentials.createInsecure();
- const collectorExporterWithTimeout = new OTLPLogsExporter({
+ const collectorExporterWithTimeout = new OTLPLogExporter({
url: 'grpcs://' + address,
credentials,
metadata: params.metadata,
@@ -229,7 +229,7 @@ const testCollectorExporter = (params: TestParams) =>
fs.readFileSync('./test/certs/client.crt')
)
: grpc.credentials.createInsecure();
- collectorExporter = new OTLPLogsExporter({
+ collectorExporter = new OTLPLogExporter({
url: 'https://' + address,
credentials,
metadata: params.metadata,
@@ -272,7 +272,7 @@ const testCollectorExporter = (params: TestParams) =>
: grpc.credentials.createInsecure();
envSource.OTEL_EXPORTER_OTLP_COMPRESSION = 'gzip';
- collectorExporter = new OTLPLogsExporter({
+ collectorExporter = new OTLPLogExporter({
url: 'https://' + address,
credentials,
metadata: params.metadata,
@@ -286,9 +286,9 @@ const testCollectorExporter = (params: TestParams) =>
});
});
-describe('OTLPLogsExporter - node (getDefaultUrl)', () => {
+describe('OTLPLogExporter - node (getDefaultUrl)', () => {
it('should default to localhost', done => {
- const collectorExporter = new OTLPLogsExporter({});
+ const collectorExporter = new OTLPLogExporter({});
setTimeout(() => {
assert.strictEqual(collectorExporter['url'], 'localhost:4317');
done();
@@ -296,7 +296,7 @@ describe('OTLPLogsExporter - node (getDefaultUrl)', () => {
});
it('should keep the URL if included', done => {
const url = 'http://foo.bar.com';
- const collectorExporter = new OTLPLogsExporter({ url });
+ const collectorExporter = new OTLPLogExporter({ url });
setTimeout(() => {
assert.strictEqual(collectorExporter['url'], 'foo.bar.com');
done();
@@ -308,21 +308,21 @@ describe('when configuring via environment', () => {
const envSource = process.env;
it('should use url defined in env', () => {
envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar';
- const collectorExporter = new OTLPLogsExporter();
+ const collectorExporter = new OTLPLogExporter();
assert.strictEqual(collectorExporter.url, 'foo.bar');
envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
});
it('should override global exporter url with signal url defined in env', () => {
envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar';
envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.logs';
- const collectorExporter = new OTLPLogsExporter();
+ const collectorExporter = new OTLPLogExporter();
assert.strictEqual(collectorExporter.url, 'foo.logs');
envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
});
it('should use headers defined via env', () => {
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar';
- const collectorExporter = new OTLPLogsExporter();
+ const collectorExporter = new OTLPLogExporter();
assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['bar']);
envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
});
@@ -332,7 +332,7 @@ describe('when configuring via environment', () => {
metadata.set('goo', 'lol');
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=jar,bar=foo';
envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=boo';
- const collectorExporter = new OTLPLogsExporter({ metadata });
+ const collectorExporter = new OTLPLogExporter({ metadata });
assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['boo']);
assert.deepStrictEqual(collectorExporter.metadata?.get('bar'), ['foo']);
assert.deepStrictEqual(collectorExporter.metadata?.get('goo'), ['lol']);
diff --git a/experimental/packages/exporter-logs-otlp-grpc/test/logsHelper.ts b/experimental/packages/exporter-logs-otlp-grpc/test/logsHelper.ts
index b57b2682bd..1dfd82675a 100644
--- a/experimental/packages/exporter-logs-otlp-grpc/test/logsHelper.ts
+++ b/experimental/packages/exporter-logs-otlp-grpc/test/logsHelper.ts
@@ -45,6 +45,7 @@ export const mockedReadableLogRecord: ReadableLogRecord = {
schemaUrl: 'http://url.to.schema',
},
hrTime: [1680253513, 123241635] as HrTime,
+ hrTimeObserved: [1683526948, 965142784] as HrTime,
attributes: {
'some-attribute': 'some attribute value',
},
@@ -92,7 +93,7 @@ export function ensureExportedLogRecordIsCorrect(logRecord: ILogRecord) {
);
assert.strictEqual(
logRecord.observedTimeUnixNano,
- '1680253513123241728',
+ '1683526948965142784',
'observedTimeUnixNano is wrong'
);
assert.strictEqual(
diff --git a/experimental/packages/exporter-logs-otlp-http/.eslintignore b/experimental/packages/exporter-logs-otlp-http/.eslintignore
new file mode 100644
index 0000000000..378eac25d3
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/.eslintignore
@@ -0,0 +1 @@
+build
diff --git a/experimental/packages/exporter-logs-otlp-http/.eslintrc.js b/experimental/packages/exporter-logs-otlp-http/.eslintrc.js
new file mode 100644
index 0000000000..f3f22e8617
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/.eslintrc.js
@@ -0,0 +1,9 @@
+module.exports = {
+ env: {
+ mocha: true,
+ commonjs: true,
+ node: true,
+ browser: true,
+ },
+ ...require('../../../eslint.config.js'),
+};
diff --git a/experimental/packages/exporter-logs-otlp-http/.npmignore b/experimental/packages/exporter-logs-otlp-http/.npmignore
new file mode 100644
index 0000000000..9505ba9450
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/.npmignore
@@ -0,0 +1,4 @@
+/bin
+/coverage
+/doc
+/test
diff --git a/experimental/packages/exporter-logs-otlp-http/LICENSE b/experimental/packages/exporter-logs-otlp-http/LICENSE
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/experimental/packages/exporter-logs-otlp-http/README.md b/experimental/packages/exporter-logs-otlp-http/README.md
new file mode 100644
index 0000000000..256e1d88d8
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/README.md
@@ -0,0 +1,114 @@
+# OpenTelemetry Collector Logs Exporter for web and node with HTTP
+
+[![NPM Published Version][npm-img]][npm-url]
+[![Apache License][license-image]][license-image]
+
+**Note: This is an experimental package under active development. New releases may include breaking changes.**
+
+This module provides an exporter for OTLP (http/json) logs using protocol version `v0.18`.
+
+## Installation
+
+```bash
+npm install --save @opentelemetry/exporter-logs-otlp-http
+```
+
+## Further Documentation
+
+To see documentation and sample code for the traces exporter, as well as instructions for using TLS, visit the [Collector Trace Exporter for web and node][trace-exporter-url].
+To see documentation and sample code for the metric exporter, see the [exporter-metrics-otlp-grpc package][metrics-exporter-url]
+
+## Logs in Web
+
+The OTLPLogExporter in Web expects the endpoint to end in `/v1/logs`.
+
+```js
+import { SeverityNumber } from '@opentelemetry/api-logs';
+import {
+ LoggerProvider,
+ BatchLogRecordProcessor,
+} from '@opentelemetry/sdk-logs';
+import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
+
+// exporter options. see all options in OTLPExporterConfigBase
+const collectorOptions = {
+ url: '', // url is optional and can be omitted - default is http://localhost:4318/v1/logs
+ headers: {}, // an optional object containing custom headers to be sent with each request
+ concurrencyLimit: 1, // an optional limit on pending requests
+};
+const logExporter = new OTLPLogExporter(collectorOptions);
+const loggerProvider = new LoggerProvider();
+
+loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
+
+const logger = loggerProvider.getLogger('default', '1.0.0');
+// Emit a log
+logger.emit({
+ severityNumber: SeverityNumber.INFO,
+ severityText: 'info',
+ body: 'this is a log body',
+ attributes: { 'log.type': 'custom' },
+});
+```
+
+## Logs in Node
+
+```js
+import {
+ LoggerProvider,
+ BatchLogRecordProcessor,
+} from '@opentelemetry/sdk-logs';
+import { OTLPLogsExporter } from '@opentelemetry/exporter-logs-otlp-http';
+
+// exporter options. see all options in OTLPExporterNodeConfigBase
+const collectorOptions = {
+ url: '', // url is optional and can be omitted - default is http://localhost:4318/v1/logs
+ concurrencyLimit: 1, // an optional limit on pending requests
+};
+const logExporter = new OTLPLogExporter(collectorOptions);
+const loggerProvider = new LoggerProvider();
+
+loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
+
+const logger = loggerProvider.getLogger('default', '1.0.0');
+// Emit a log
+logger.emit({
+ severityNumber: SeverityNumber.INFO,
+ severityText: 'info',
+ body: 'this is a log body',
+ attributes: { 'log.type': 'custom' },
+});
+```
+
+## Environment Variable Configuration
+
+In addition to settings passed to the constructor, the exporter also supports configuration via environment variables:
+
+| Environment variable | Description |
+| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| OTEL_EXPORTER_OTLP_ENDPOINT | The endpoint to send logs to. This will also be used for the traces exporter if `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` is not configured. By default `http://localhost:4318` will be used. `/v1/logs` will be automatically appended to configured values. |
+| OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | The endpoint to send logs to. By default `https://localhost:4318/v1/logs` will be used. `v1/logs` will not be appended automatically and has to be added explicitly. |
+| OTEL_EXPORTER_OTLP_LOGS_TIMEOUT | The maximum waiting time, in milliseconds, allowed to send each OTLP log batch. Default is 10000. |
+| OTEL_EXPORTER_OTLP_TIMEOUT | The maximum waiting time, in milliseconds, allowed to send each OTLP trace/metric/log batch. Default is 10000. |
+
+> Settings configured programmatically take precedence over environment variables. Per-signal environment variables take precedence over non-per-signal environment variables.
+
+## Useful links
+
+- For more information on OpenTelemetry, visit:
+- For more about OpenTelemetry JavaScript:
+- For help or feedback on this project, join us in [GitHub Discussions][discussions-url]
+
+## License
+
+Apache 2.0 - See [LICENSE][license-url] for more information.
+
+[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions
+[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/LICENSE
+[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
+[npm-url]: https://www.npmjs.com/package/@opentelemetry/exporter-logs-otlp-http
+[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fexporter-logs-otlp-http.svg
+[opentelemetry-collector-url]: https://github.com/open-telemetry/opentelemetry-collector
+[semconv-resource-service-name]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service
+[trace-exporter-url]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/exporter-trace-otlp-http
+[metrics-exporter-url]: https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-metrics-otlp-http
diff --git a/experimental/packages/exporter-logs-otlp-http/karma.conf.js b/experimental/packages/exporter-logs-otlp-http/karma.conf.js
new file mode 100644
index 0000000000..bfd7a03326
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/karma.conf.js
@@ -0,0 +1,28 @@
+/*!
+ * 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'] },
+ })
+ );
+};
diff --git a/experimental/packages/exporter-logs-otlp-http/package.json b/experimental/packages/exporter-logs-otlp-http/package.json
new file mode 100644
index 0000000000..b6f4808b42
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/package.json
@@ -0,0 +1,109 @@
+{
+ "name": "@opentelemetry/exporter-logs-otlp-http",
+ "version": "0.39.1",
+ "publishConfig": {
+ "access": "public"
+ },
+ "description": "OpenTelemetry Collector Logs Exporter allows user to send collected logs to the OpenTelemetry Collector",
+ "author": "OpenTelemetry Authors",
+ "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/exporter-logs-otlp-http",
+ "license": "Apache-2.0",
+ "main": "build/src/index.js",
+ "module": "build/esm/index.js",
+ "esnext": "build/esnext/index.js",
+ "types": "build/src/index.d.ts",
+ "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"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/open-telemetry/opentelemetry-js.git"
+ },
+ "bugs": {
+ "url": "https://github.com/open-telemetry/opentelemetry-js/issues"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "scripts": {
+ "prepublishOnly": "npm run compile",
+ "compile": "tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json",
+ "clean": "tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json",
+ "codecov:browser": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../../",
+ "lint": "eslint . --ext .ts",
+ "lint:fix": "eslint . --ext .ts --fix",
+ "tdd": "npm run test -- --watch-extensions ts --watch",
+ "tdd:browser": "karma start",
+ "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 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",
+ "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../../"
+ },
+ "keywords": [
+ "opentelemetry",
+ "nodejs",
+ "browser",
+ "tracing",
+ "profiling",
+ "logs",
+ "stats"
+ ],
+ "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",
+ "doc",
+ "LICENSE",
+ "README.md"
+ ],
+ "sideEffects": false,
+ "devDependencies": {
+ "@babel/core": "7.16.0",
+ "@opentelemetry/api-logs": ">=0.38.0",
+ "@types/mocha": "10.0.0",
+ "@types/node": "18.6.5",
+ "@types/sinon": "10.0.13",
+ "@types/webpack-env": "1.16.3",
+ "babel-loader": "8.2.3",
+ "codecov": "3.8.3",
+ "cpx": "1.5.0",
+ "istanbul-instrumenter-loader": "3.0.1",
+ "karma": "6.3.16",
+ "karma-chrome-launcher": "3.1.0",
+ "karma-coverage-istanbul-reporter": "3.0.3",
+ "karma-mocha": "2.0.1",
+ "karma-spec-reporter": "0.0.32",
+ "karma-webpack": "4.0.2",
+ "mocha": "10.0.0",
+ "nyc": "15.1.0",
+ "sinon": "14.0.0",
+ "ts-loader": "8.4.0",
+ "ts-mocha": "10.0.0",
+ "typescript": "4.4.4",
+ "webpack": "4.46.0",
+ "webpack-cli": "4.9.1",
+ "webpack-merge": "5.8.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api-logs": ">=0.38.0"
+ },
+ "dependencies": {
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/sdk-logs": "0.39.1"
+ }
+}
diff --git a/experimental/packages/exporter-logs-otlp-http/src/index.ts b/experimental/packages/exporter-logs-otlp-http/src/index.ts
new file mode 100644
index 0000000000..89954d4784
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/src/index.ts
@@ -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 { OTLPLogExporter } from './platform';
diff --git a/experimental/packages/exporter-logs-otlp-http/src/platform/browser/OTLPLogExporter.ts b/experimental/packages/exporter-logs-otlp-http/src/platform/browser/OTLPLogExporter.ts
new file mode 100644
index 0000000000..ef837614e2
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/src/platform/browser/OTLPLogExporter.ts
@@ -0,0 +1,57 @@
+/*
+ * 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 type {
+ ReadableLogRecord,
+ LogRecordExporter,
+} from '@opentelemetry/sdk-logs';
+import type { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base';
+import type { IExportLogsServiceRequest } from '@opentelemetry/otlp-transformer';
+import { OTLPExporterBrowserBase } from '@opentelemetry/otlp-exporter-base';
+import { baggageUtils, getEnv } from '@opentelemetry/core';
+import { createExportLogsServiceRequest } from '@opentelemetry/otlp-transformer';
+
+import { getDefaultUrl } from '../config';
+
+/**
+ * Collector Logs Exporter for Web
+ */
+export class OTLPLogExporter
+ extends OTLPExporterBrowserBase
+ implements LogRecordExporter
+{
+ constructor(config: OTLPExporterConfigBase = {}) {
+ // load OTEL_EXPORTER_OTLP_LOGS_TIMEOUT env var
+ super({
+ timeoutMillis: getEnv().OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
+ ...config,
+ });
+ this._headers = {
+ ...this._headers,
+ ...baggageUtils.parseKeyPairsIntoRecord(
+ getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
+ ),
+ };
+ }
+
+ convert(logRecords: ReadableLogRecord[]): IExportLogsServiceRequest {
+ return createExportLogsServiceRequest(logRecords);
+ }
+
+ getDefaultUrl(config: OTLPExporterConfigBase): string {
+ return getDefaultUrl(config);
+ }
+}
diff --git a/experimental/packages/exporter-logs-otlp-http/src/platform/browser/index.ts b/experimental/packages/exporter-logs-otlp-http/src/platform/browser/index.ts
new file mode 100644
index 0000000000..2472e4a796
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/src/platform/browser/index.ts
@@ -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 { OTLPLogExporter } from './OTLPLogExporter';
diff --git a/experimental/packages/exporter-logs-otlp-http/src/platform/config.ts b/experimental/packages/exporter-logs-otlp-http/src/platform/config.ts
new file mode 100644
index 0000000000..a41ee96468
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/src/platform/config.ts
@@ -0,0 +1,43 @@
+/*
+ * 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 { getEnv } from '@opentelemetry/core';
+import {
+ appendResourcePathToUrl,
+ appendRootPathToUrlIfNeeded,
+ OTLPExporterConfigBase,
+} from '@opentelemetry/otlp-exporter-base';
+
+const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/logs';
+export const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
+
+/**
+ * common get default url
+ * @param config exporter config
+ * @returns url string
+ */
+export function getDefaultUrl(config: OTLPExporterConfigBase): string {
+ return typeof config.url === 'string'
+ ? config.url
+ : getEnv().OTEL_EXPORTER_OTLP_LOGS_ENDPOINT.length > 0
+ ? appendRootPathToUrlIfNeeded(getEnv().OTEL_EXPORTER_OTLP_LOGS_ENDPOINT)
+ : getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
+ ? appendResourcePathToUrl(
+ getEnv().OTEL_EXPORTER_OTLP_ENDPOINT,
+ DEFAULT_COLLECTOR_RESOURCE_PATH
+ )
+ : DEFAULT_COLLECTOR_URL;
+}
diff --git a/experimental/packages/exporter-logs-otlp-http/src/platform/index.ts b/experimental/packages/exporter-logs-otlp-http/src/platform/index.ts
new file mode 100644
index 0000000000..830bf10b27
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/src/platform/index.ts
@@ -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 { OTLPLogExporter } from './node';
diff --git a/experimental/packages/exporter-logs-otlp-http/src/platform/node/OTLPLogExporter.ts b/experimental/packages/exporter-logs-otlp-http/src/platform/node/OTLPLogExporter.ts
new file mode 100644
index 0000000000..7f7c538df7
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/src/platform/node/OTLPLogExporter.ts
@@ -0,0 +1,57 @@
+/*
+ * 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 type {
+ ReadableLogRecord,
+ LogRecordExporter,
+} from '@opentelemetry/sdk-logs';
+import type { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
+import type { IExportLogsServiceRequest } from '@opentelemetry/otlp-transformer';
+import { getEnv, baggageUtils } from '@opentelemetry/core';
+import { OTLPExporterNodeBase } from '@opentelemetry/otlp-exporter-base';
+import { createExportLogsServiceRequest } from '@opentelemetry/otlp-transformer';
+
+import { getDefaultUrl } from '../config';
+
+/**
+ * Collector Logs Exporter for Node
+ */
+export class OTLPLogExporter
+ extends OTLPExporterNodeBase
+ implements LogRecordExporter
+{
+ constructor(config: OTLPExporterNodeConfigBase = {}) {
+ // load OTEL_EXPORTER_OTLP_LOGS_TIMEOUT env
+ super({
+ timeoutMillis: getEnv().OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
+ ...config,
+ });
+ this.headers = {
+ ...this.headers,
+ ...baggageUtils.parseKeyPairsIntoRecord(
+ getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
+ ),
+ };
+ }
+
+ convert(logRecords: ReadableLogRecord[]): IExportLogsServiceRequest {
+ return createExportLogsServiceRequest(logRecords);
+ }
+
+ getDefaultUrl(config: OTLPExporterNodeConfigBase): string {
+ return getDefaultUrl(config);
+ }
+}
diff --git a/experimental/packages/exporter-logs-otlp-http/src/platform/node/index.ts b/experimental/packages/exporter-logs-otlp-http/src/platform/node/index.ts
new file mode 100644
index 0000000000..2472e4a796
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/src/platform/node/index.ts
@@ -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 { OTLPLogExporter } from './OTLPLogExporter';
diff --git a/experimental/packages/exporter-logs-otlp-http/test/browser/OTLPLogExporter.test.ts b/experimental/packages/exporter-logs-otlp-http/test/browser/OTLPLogExporter.test.ts
new file mode 100644
index 0000000000..66958a9fef
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/test/browser/OTLPLogExporter.test.ts
@@ -0,0 +1,64 @@
+/*
+ * 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 * as Config from '../../src/platform/config';
+import { OTLPLogExporter } from '../../src/platform/browser';
+
+describe('OTLPLogExporter', () => {
+ let envSource: Record;
+
+ if (typeof process === 'undefined') {
+ envSource = globalThis as unknown as Record;
+ } else {
+ envSource = process.env as Record;
+ }
+
+ describe('constructor', () => {
+ it('should create an instance', () => {
+ const exporter = new OTLPLogExporter();
+ assert.ok(exporter instanceof OTLPLogExporter);
+ });
+
+ it('should use headers defined via env', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=bar';
+ const exporter = new OTLPLogExporter();
+ assert.strictEqual(exporter['_headers'].foo, 'bar');
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS;
+ });
+
+ it('should use timeout defined via env', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = '';
+ envSource.OTEL_EXPORTER_OTLP_LOGS_TIMEOUT = 30000;
+ const exporter = new OTLPLogExporter();
+ assert.strictEqual(exporter.timeoutMillis, 30000);
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS;
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS;
+ });
+ });
+
+ describe('getDefaultUrl', () => {
+ it('should call getDefaultUrl', () => {
+ const getDefaultUrl = sinon.stub(Config, 'getDefaultUrl');
+ const exporter = new OTLPLogExporter();
+ exporter.getDefaultUrl({});
+ // this callCount is 2, because new OTLPLogExporter also call it
+ assert.strictEqual(getDefaultUrl.callCount, 2);
+ });
+ });
+});
diff --git a/experimental/packages/exporter-logs-otlp-http/test/browser/index-webpack.ts b/experimental/packages/exporter-logs-otlp-http/test/browser/index-webpack.ts
new file mode 100644
index 0000000000..9a4c86560e
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/test/browser/index-webpack.ts
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+{
+ const testsContext = require.context('../browser', true, /test$/);
+ testsContext.keys().forEach(testsContext);
+}
diff --git a/experimental/packages/exporter-logs-otlp-http/test/config.test.ts b/experimental/packages/exporter-logs-otlp-http/test/config.test.ts
new file mode 100644
index 0000000000..77656de561
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/test/config.test.ts
@@ -0,0 +1,136 @@
+/*
+ * 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 { getDefaultUrl } from '../src/platform/config';
+
+describe('getDefaultUrl', () => {
+ let envSource: Record;
+
+ if (typeof process === 'undefined') {
+ envSource = globalThis as unknown as Record;
+ } else {
+ envSource = process.env as Record;
+ }
+
+ it('should use config url if config url is defined', () => {
+ const configUrl = 'http://foo.bar/v1/logs/';
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar.logs/';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar/';
+ const defaultUrl = getDefaultUrl({ url: configUrl });
+ assert.strictEqual(defaultUrl, configUrl);
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should use url defined in env that ends with root path and append version and signal path', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar/';
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_ENDPOINT}v1/logs`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should use url defined in env without checking if path is already present', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar/v1/logs';
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/logs`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should use url defined in env and append version and signal', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar';
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/logs`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should override global exporter url with signal url defined in env', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.logs/';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar/';
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should add root path when signal url defined in env contains no path and no root path', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.logs';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}/`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should not add root path when signal url defined in env contains root path but no path', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar/';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should not add root path when signal url defined in env contains path', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar/v1/logs';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+
+ it('should not add root path when signal url defined in env contains path and ends in /', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar/v1/logs/';
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+ const defaultUrl = getDefaultUrl({});
+ assert.strictEqual(
+ defaultUrl,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}`
+ );
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
+ delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
+ });
+});
diff --git a/experimental/packages/exporter-logs-otlp-http/test/node/OTLPLogExporter.test.ts b/experimental/packages/exporter-logs-otlp-http/test/node/OTLPLogExporter.test.ts
new file mode 100644
index 0000000000..aa0d345348
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/test/node/OTLPLogExporter.test.ts
@@ -0,0 +1,64 @@
+/*
+ * 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 * as Config from '../../src/platform/config';
+import { OTLPLogExporter } from '../../src/platform/node';
+
+describe('OTLPLogExporter', () => {
+ let envSource: Record;
+
+ if (typeof process === 'undefined') {
+ envSource = globalThis as unknown as Record;
+ } else {
+ envSource = process.env as Record;
+ }
+
+ describe('constructor', () => {
+ it('should create an instance', () => {
+ const exporter = new OTLPLogExporter();
+ assert.ok(exporter instanceof OTLPLogExporter);
+ });
+
+ it('should use headers defined via env', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=bar';
+ const exporter = new OTLPLogExporter();
+ assert.strictEqual(exporter.headers.foo, 'bar');
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS;
+ });
+
+ it('should use timeout defined via env', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = '';
+ envSource.OTEL_EXPORTER_OTLP_LOGS_TIMEOUT = 30000;
+ const exporter = new OTLPLogExporter();
+ assert.strictEqual(exporter.timeoutMillis, 30000);
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS;
+ delete envSource.OTEL_EXPORTER_OTLP_LOGS_TIMEOUT;
+ });
+ });
+
+ describe('getDefaultUrl', () => {
+ it('should call getDefaultUrl', () => {
+ const getDefaultUrl = sinon.stub(Config, 'getDefaultUrl');
+ const exporter = new OTLPLogExporter();
+ exporter.getDefaultUrl({});
+ // this callCount is 2, because new OTLPLogExporter also call it
+ assert.strictEqual(getDefaultUrl.callCount, 2);
+ });
+ });
+});
diff --git a/experimental/packages/exporter-logs-otlp-http/tsconfig.esm.json b/experimental/packages/exporter-logs-otlp-http/tsconfig.esm.json
new file mode 100644
index 0000000000..554367c373
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/tsconfig.esm.json
@@ -0,0 +1,28 @@
+{
+ "extends": "../../../tsconfig.base.esm.json",
+ "compilerOptions": {
+ "outDir": "build/esm",
+ "rootDir": "src",
+ "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo"
+ },
+ "include": [
+ "src/**/*.ts"
+ ],
+ "references": [
+ {
+ "path": "../../../packages/opentelemetry-core"
+ },
+ {
+ "path": "../api-logs"
+ },
+ {
+ "path": "../otlp-exporter-base"
+ },
+ {
+ "path": "../otlp-transformer"
+ },
+ {
+ "path": "../sdk-logs"
+ }
+ ]
+}
diff --git a/experimental/packages/exporter-logs-otlp-http/tsconfig.esnext.json b/experimental/packages/exporter-logs-otlp-http/tsconfig.esnext.json
new file mode 100644
index 0000000000..87a369521c
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/tsconfig.esnext.json
@@ -0,0 +1,28 @@
+{
+ "extends": "../../../tsconfig.base.esnext.json",
+ "compilerOptions": {
+ "outDir": "build/esnext",
+ "rootDir": "src",
+ "tsBuildInfoFile": "build/esnext/tsconfig.esnext.tsbuildinfo"
+ },
+ "include": [
+ "src/**/*.ts"
+ ],
+ "references": [
+ {
+ "path": "../../../packages/opentelemetry-core"
+ },
+ {
+ "path": "../api-logs"
+ },
+ {
+ "path": "../otlp-exporter-base"
+ },
+ {
+ "path": "../otlp-transformer"
+ },
+ {
+ "path": "../sdk-logs"
+ }
+ ]
+}
diff --git a/experimental/packages/exporter-logs-otlp-http/tsconfig.json b/experimental/packages/exporter-logs-otlp-http/tsconfig.json
new file mode 100644
index 0000000000..c4eda837a9
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-http/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "esModuleInterop": true,
+ "outDir": "build",
+ "rootDir": "."
+ },
+ "include": [
+ "src/**/*.ts",
+ "test/**/*.ts"
+ ],
+ "references": [
+ {
+ "path": "../../../packages/opentelemetry-core"
+ },
+ {
+ "path": "../api-logs"
+ },
+ {
+ "path": "../otlp-exporter-base"
+ },
+ {
+ "path": "../otlp-transformer"
+ },
+ {
+ "path": "../sdk-logs"
+ }
+ ]
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/.eslintignore b/experimental/packages/exporter-logs-otlp-proto/.eslintignore
new file mode 100644
index 0000000000..378eac25d3
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/.eslintignore
@@ -0,0 +1 @@
+build
diff --git a/experimental/packages/exporter-logs-otlp-proto/.eslintrc.js b/experimental/packages/exporter-logs-otlp-proto/.eslintrc.js
new file mode 100644
index 0000000000..3ed0fbeba3
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/.eslintrc.js
@@ -0,0 +1,8 @@
+module.exports = {
+ "env": {
+ "mocha": true,
+ "commonjs": true,
+ "node": true,
+ },
+ ...require('../../../eslint.config.js')
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/.npmignore b/experimental/packages/exporter-logs-otlp-proto/.npmignore
new file mode 100644
index 0000000000..9505ba9450
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/.npmignore
@@ -0,0 +1,4 @@
+/bin
+/coverage
+/doc
+/test
diff --git a/experimental/packages/exporter-logs-otlp-proto/LICENSE b/experimental/packages/exporter-logs-otlp-proto/LICENSE
new file mode 100644
index 0000000000..261eeb9e9f
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/experimental/packages/exporter-logs-otlp-proto/README.md b/experimental/packages/exporter-logs-otlp-proto/README.md
new file mode 100644
index 0000000000..3019f50d3f
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/README.md
@@ -0,0 +1,110 @@
+# An OTLP exporter to send logs using protobuf over HTTP
+
+[![NPM Published Version][npm-img]][npm-url]
+[![Apache License][license-image]][license-image]
+
+**Note: This is an experimental package under active development. New releases may include breaking changes.**
+
+This module provides an exporter for OTLP (http/protobuf) logs using protocol version `v0.18`.
+
+## Installation
+
+```bash
+npm install --save @opentelemetry/exporter-logs-otlp-proto
+```
+
+## Further Documentation
+
+To see documentation and sample code for the traces exporter, as well as instructions for using TLS, see the [exporter-trace-otlp-proto package][trace-exporter-url].
+To see documentation and sample code for the metric exporter, see the [exporter-trace-otlp-proto package][metrics-exporter-url].
+
+## Example Setup
+
+```js
+const { LoggerProvider, SimpleLogRecordProcessor } = require('@opentelemetry/sdk-logs');
+const { OTLPLogsExporter } = require('@opentelemetry/exporter-logs-otlp-proto');
+
+const collectorOptions = {
+ url: '', // url is optional and can be omitted - default is http://localhost:4318/v1/logs
+ headers: {
+ foo: 'bar'
+ }, //an optional object containing custom headers to be sent with each request will only work with http
+};
+
+const logProvider = new LoggerProvider({resource: new Resource({'service.name': 'testApp'})});
+const logExporter = new OTLPLogsExporter(collectorOptions);
+logProvider.addLogRecordProcessor(new SimpleLogRecordProcessor(exporter));
+
+const logger = logProvider.getLogger('test_log_instrumentation');
+
+logger.emit({
+ //log data to emit
+})
+```
+
+## Exporter Timeout Configuration
+
+The OTLPLogsExporter has a timeout configuration option which is the maximum time, in milliseconds, the OTLP exporter will wait for each batch export. The default value is 10000ms.
+
+To override the default timeout duration, use the following options:
+
++ Set with environment variables:
+
+ | Environment variable | Description |
+------------------------------|----------------------|-------------|
+ | OTEL_EXPORTER_OTLP_LOGS_TIMEOUT | The maximum waiting time, in milliseconds, allowed to send each OTLP trace batch. Default is 10000. |
+ | OTEL_EXPORTER_OTLP_TIMEOUT | The maximum waiting time, in milliseconds, allowed to send each OTLP trace and metric batch. Default is 10000. |
+
+ > `OTEL_EXPORTER_OTLP_LOGS_TIMEOUT` takes precedence and overrides `OTEL_EXPORTER_OTLP_TIMEOUT`.
+
++ Provide `timeoutMillis` to OTLPLogsExporter with `collectorOptions`:
+
+ ```js
+ const collectorOptions = {
+ timeoutMillis: 15000,
+ url: '', // url is optional and can be omitted - default is http://localhost:4318/v1/logs
+ headers: {
+ foo: 'bar'
+ }, //an optional object containing custom headers to be sent with each request will only work with http
+ };
+
+ const exporter = new OTLPLogsExporter(collectorOptions);
+ ```
+
+ > Providing `timeoutMillis` with `collectorOptions` takes precedence and overrides timeout set with environment variables.
+
+## OTLP Exporter Retry
+
+OTLP requires that transient errors be handled with a [retry strategy](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#retry).
+
+This retry policy has the following configuration, which there is currently no way to customize.
+
++ `DEFAULT_EXPORT_MAX_ATTEMPTS`: The maximum number of attempts, including the original request. Defaults to 5.
++ `DEFAULT_EXPORT_INITIAL_BACKOFF`: The initial backoff duration. Defaults to 1 second.
++ `DEFAULT_EXPORT_MAX_BACKOFF`: The maximum backoff duration. Defaults to 5 seconds.
++ `DEFAULT_EXPORT_BACKOFF_MULTIPLIER`: The backoff multiplier. Defaults to 1.5.
+
+This retry policy first checks if the response has a `'Retry-After'` header. If there is a `'Retry-After'` header, the exporter will wait the amount specified in the `'Retry-After'` header before retrying. If there is no `'Retry-After'` header, the exporter will use an exponential backoff with jitter retry strategy.
+
+ > The exporter will retry exporting within the [exporter timeout configuration](#Exporter-Timeout-Configuration) time.
+
+## Useful links
+
++ For more information on OpenTelemetry, visit:
++ For more about OpenTelemetry JavaScript:
++ For help or feedback on this project, join us in [GitHub Discussions][discussions-url]
+
+## License
+
+Apache 2.0 - See [LICENSE][license-url] for more information.
+
+[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions
+[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/LICENSE
+[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
+[npm-url]: https://www.npmjs.com/package/@opentelemetry/exporter-logs-otlp-proto
+[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fexporter-logs-otlp-proto.svg
+[opentelemetry-collector-url]: https://github.com/open-telemetry/opentelemetry-collector
+[semconv-resource-service-name]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service
+[logs-exporter-url]: https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-logs-otlp-proto
+[trace-exporter-url]: https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/exporter-trace-otlp-proto
+[metrics-exporter-url]: https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-metrics-otlp-proto
diff --git a/experimental/packages/exporter-logs-otlp-proto/karma.conf.js b/experimental/packages/exporter-logs-otlp-proto/karma.conf.js
new file mode 100644
index 0000000000..4c60b54edb
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/karma.conf.js
@@ -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'] }
+ }))
+};
diff --git a/experimental/packages/exporter-logs-otlp-proto/package.json b/experimental/packages/exporter-logs-otlp-proto/package.json
new file mode 100644
index 0000000000..016ec13486
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/package.json
@@ -0,0 +1,95 @@
+{
+ "name": "@opentelemetry/exporter-logs-otlp-proto",
+ "version": "0.39.1",
+ "description": "An OTLP exporter to send logs using protobuf over HTTP",
+ "main": "build/src/index.js",
+ "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 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' --exclude 'test/browser/**/*.ts'",
+ "test:browser": "nyc karma start --single-run",
+ "version": "node ../../../scripts/version-update.js",
+ "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",
+ "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../../"
+ },
+ "keywords": [
+ "opentelemetry",
+ "nodejs",
+ "protobuf",
+ "tracing",
+ "profiling",
+ "metrics",
+ "stats",
+ "logs"
+ ],
+ "author": "OpenTelemetry Authors",
+ "license": "Apache-2.0",
+ "engines": {
+ "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",
+ "build/protos/**/*.proto",
+ "doc",
+ "LICENSE",
+ "README.md"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "devDependencies": {
+ "@babel/core": "7.16.0",
+ "@opentelemetry/api": "1.4.1",
+ "@types/mocha": "10.0.0",
+ "@types/node": "18.6.5",
+ "@types/sinon": "10.0.13",
+ "codecov": "3.8.3",
+ "cpx": "1.5.0",
+ "mocha": "10.0.0",
+ "nyc": "15.1.0",
+ "sinon": "15.0.0",
+ "ts-loader": "8.4.0",
+ "ts-mocha": "10.0.0",
+ "typescript": "4.4.4"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.0.0"
+ },
+ "dependencies": {
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/api-logs": "^0.39.1",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-proto-exporter-base": "0.39.1",
+ "@opentelemetry/sdk-logs": "^0.39.1"
+ },
+ "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/exporter-logs-otlp-proto",
+ "sideEffects": false
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/src/index.ts b/experimental/packages/exporter-logs-otlp-proto/src/index.ts
new file mode 100644
index 0000000000..9fde4be45b
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/src/index.ts
@@ -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 { OTLPLogsExporter } from './platform';
diff --git a/experimental/packages/exporter-logs-otlp-proto/src/platform/browser/OTLPLogsExporter.ts b/experimental/packages/exporter-logs-otlp-proto/src/platform/browser/OTLPLogsExporter.ts
new file mode 100644
index 0000000000..185d5094f1
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/src/platform/browser/OTLPLogsExporter.ts
@@ -0,0 +1,76 @@
+/*
+ * 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 { getEnv, baggageUtils } from '@opentelemetry/core';
+import {
+ OTLPExporterConfigBase,
+ appendResourcePathToUrl,
+ appendRootPathToUrlIfNeeded,
+} from '@opentelemetry/otlp-exporter-base';
+import {
+ OTLPProtoExporterBrowserBase,
+ ServiceClientType,
+} from '@opentelemetry/otlp-proto-exporter-base';
+import {
+ createExportLogsServiceRequest,
+ IExportLogsServiceRequest,
+} from '@opentelemetry/otlp-transformer';
+
+import { ReadableLogRecord, LogRecordExporter } from '@opentelemetry/sdk-logs';
+
+const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/logs';
+const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
+
+/**
+ * Collector Trace Exporter for Web
+ */
+export class OTLPLogsExporter
+ extends OTLPProtoExporterBrowserBase<
+ ReadableLogRecord,
+ IExportLogsServiceRequest
+ >
+ implements LogRecordExporter
+{
+ constructor(config: OTLPExporterConfigBase = {}) {
+ super(config);
+ this._headers = Object.assign(
+ this._headers,
+ baggageUtils.parseKeyPairsIntoRecord(
+ getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
+ )
+ );
+ }
+ convert(logs: ReadableLogRecord[]): IExportLogsServiceRequest {
+ return createExportLogsServiceRequest(logs);
+ }
+
+ getDefaultUrl(config: OTLPExporterConfigBase): string {
+ return typeof config.url === 'string'
+ ? config.url
+ : getEnv().OTEL_EXPORTER_OTLP_LOGS_ENDPOINT.length > 0
+ ? appendRootPathToUrlIfNeeded(getEnv().OTEL_EXPORTER_OTLP_LOGS_ENDPOINT)
+ : getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
+ ? appendResourcePathToUrl(
+ getEnv().OTEL_EXPORTER_OTLP_ENDPOINT,
+ DEFAULT_COLLECTOR_RESOURCE_PATH
+ )
+ : DEFAULT_COLLECTOR_URL;
+ }
+
+ getServiceClientType() {
+ return ServiceClientType.LOGS;
+ }
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/src/platform/browser/index.ts b/experimental/packages/exporter-logs-otlp-proto/src/platform/browser/index.ts
new file mode 100644
index 0000000000..e6968b3466
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/src/platform/browser/index.ts
@@ -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 { OTLPLogsExporter } from './OTLPLogsExporter';
diff --git a/experimental/packages/exporter-logs-otlp-proto/src/platform/index.ts b/experimental/packages/exporter-logs-otlp-proto/src/platform/index.ts
new file mode 100644
index 0000000000..851ff9a015
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/src/platform/index.ts
@@ -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 { OTLPLogsExporter } from './node';
diff --git a/experimental/packages/exporter-logs-otlp-proto/src/platform/node/OTLPLogsExporter.ts b/experimental/packages/exporter-logs-otlp-proto/src/platform/node/OTLPLogsExporter.ts
new file mode 100644
index 0000000000..88d97e21d3
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/src/platform/node/OTLPLogsExporter.ts
@@ -0,0 +1,76 @@
+/*
+ * 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 { getEnv, baggageUtils } from '@opentelemetry/core';
+import {
+ OTLPExporterConfigBase,
+ appendResourcePathToUrl,
+ appendRootPathToUrlIfNeeded,
+} from '@opentelemetry/otlp-exporter-base';
+import {
+ OTLPProtoExporterNodeBase,
+ ServiceClientType,
+} from '@opentelemetry/otlp-proto-exporter-base';
+import {
+ createExportLogsServiceRequest,
+ IExportLogsServiceRequest,
+} from '@opentelemetry/otlp-transformer';
+
+import { ReadableLogRecord, LogRecordExporter } from '@opentelemetry/sdk-logs';
+
+const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/logs';
+const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
+
+/**
+ * Collector Trace Exporter for Node
+ */
+export class OTLPLogsExporter
+ extends OTLPProtoExporterNodeBase<
+ ReadableLogRecord,
+ IExportLogsServiceRequest
+ >
+ implements LogRecordExporter
+{
+ constructor(config: OTLPExporterConfigBase = {}) {
+ super(config);
+ this.headers = Object.assign(
+ this.headers,
+ baggageUtils.parseKeyPairsIntoRecord(
+ getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
+ )
+ );
+ }
+ convert(logs: ReadableLogRecord[]): IExportLogsServiceRequest {
+ return createExportLogsServiceRequest(logs);
+ }
+
+ getDefaultUrl(config: OTLPExporterConfigBase): string {
+ return typeof config.url === 'string'
+ ? config.url
+ : getEnv().OTEL_EXPORTER_OTLP_LOGS_ENDPOINT.length > 0
+ ? appendRootPathToUrlIfNeeded(getEnv().OTEL_EXPORTER_OTLP_LOGS_ENDPOINT)
+ : getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
+ ? appendResourcePathToUrl(
+ getEnv().OTEL_EXPORTER_OTLP_ENDPOINT,
+ DEFAULT_COLLECTOR_RESOURCE_PATH
+ )
+ : DEFAULT_COLLECTOR_URL;
+ }
+
+ getServiceClientType() {
+ return ServiceClientType.LOGS;
+ }
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/src/platform/node/index.ts b/experimental/packages/exporter-logs-otlp-proto/src/platform/node/index.ts
new file mode 100644
index 0000000000..4797b30651
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/src/platform/node/index.ts
@@ -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 { OTLPLogsExporter } from './OTLPLogsExporter';
diff --git a/experimental/packages/exporter-logs-otlp-proto/test/browser/OTLPLogsExporter.test.ts b/experimental/packages/exporter-logs-otlp-proto/test/browser/OTLPLogsExporter.test.ts
new file mode 100644
index 0000000000..382a132c3e
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/test/browser/OTLPLogsExporter.test.ts
@@ -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 { OTLPLogsExporter } from '../../src/platform/browser/index';
+
+describe('OTLPLogsExporter - web', () => {
+ let collectorLogsExporter: OTLPLogsExporter;
+ describe('constructor', () => {
+ let onInitSpy: any;
+ beforeEach(() => {
+ onInitSpy = sinon.stub(OTLPLogsExporter.prototype, 'onInit');
+ const collectorExporterConfig = {
+ hostname: 'foo',
+ url: 'http://foo.bar.com',
+ };
+ collectorLogsExporter = new OTLPLogsExporter(collectorExporterConfig);
+ });
+ afterEach(() => {
+ sinon.restore();
+ });
+ it('should create an instance', () => {
+ assert.ok(typeof collectorLogsExporter !== 'undefined');
+ });
+ it('should call onInit', () => {
+ assert.strictEqual(onInitSpy.callCount, 1);
+ });
+ it('should set hostname', () => {
+ assert.strictEqual(collectorLogsExporter.hostname, 'foo');
+ });
+
+ it('should set url', () => {
+ assert.strictEqual(collectorLogsExporter.url, 'http://foo.bar.com');
+ });
+ });
+});
diff --git a/experimental/packages/exporter-logs-otlp-proto/test/browser/index-webpack.ts b/experimental/packages/exporter-logs-otlp-proto/test/browser/index-webpack.ts
new file mode 100644
index 0000000000..ae7d4b5a9d
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/test/browser/index-webpack.ts
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+const testsContext = require.context('../browser', true, /test$/);
+testsContext.keys().forEach(testsContext);
+
+const srcContext = require.context('.', true, /src$/);
+srcContext.keys().forEach(srcContext);
diff --git a/experimental/packages/exporter-logs-otlp-proto/test/logHelper.ts b/experimental/packages/exporter-logs-otlp-proto/test/logHelper.ts
new file mode 100644
index 0000000000..7b8c8e8b9a
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/test/logHelper.ts
@@ -0,0 +1,186 @@
+/*
+ * 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 { HrTime, TraceFlags } from '@opentelemetry/api';
+import { SeverityNumber } from '@opentelemetry/api-logs';
+import { Resource } from '@opentelemetry/resources';
+import * as assert from 'assert';
+import { VERSION } from '@opentelemetry/core';
+import {
+ IAnyValue,
+ IExportLogsServiceRequest,
+ IKeyValue,
+ ILogRecord,
+ IResource,
+} from '@opentelemetry/otlp-transformer';
+import { ReadableLogRecord } from '@opentelemetry/sdk-logs';
+import { Stream } from 'stream';
+
+export const mockedReadableLogRecord: ReadableLogRecord = {
+ resource: Resource.default().merge(
+ new Resource({
+ 'resource-attribute': 'some resource-attr value',
+ })
+ ),
+ instrumentationScope: {
+ name: 'scope_name_1',
+ version: '0.1.0',
+ schemaUrl: 'http://url.to.schema',
+ },
+ hrTime: [1680253513, 123241635] as HrTime,
+ hrTimeObserved: [1680253513, 123241635] as HrTime,
+ attributes: {
+ 'some-attribute': 'some attribute value',
+ },
+ severityNumber: SeverityNumber.ERROR,
+ severityText: 'error',
+ body: 'some_log_body',
+ spanContext: {
+ traceFlags: TraceFlags.SAMPLED,
+ traceId: '1f1008dc8e270e85c40a0d7c3939b278',
+ spanId: '5e107261f64fa53e',
+ },
+};
+export function ensureExportedAttributesAreCorrect(attributes: IKeyValue[]) {
+ assert.deepStrictEqual(
+ attributes,
+ [
+ {
+ key: 'some-attribute',
+ value: {
+ stringValue: 'some attribute value',
+ },
+ },
+ ],
+ 'exported attributes are incorrect'
+ );
+}
+
+export function ensureExportedBodyIsCorrect(body?: IAnyValue) {
+ assert.deepStrictEqual(
+ body,
+ { stringValue: 'some_log_body' },
+ 'exported attributes are incorrect'
+ );
+}
+
+export function ensureExportedLogRecordIsCorrect(logRecord: ILogRecord) {
+ ensureExportedBodyIsCorrect(logRecord.body);
+ ensureExportedAttributesAreCorrect(logRecord.attributes);
+ assert.strictEqual(
+ logRecord.timeUnixNano,
+ '1680253513123241728',
+ 'timeUnixNano is wrong'
+ );
+ assert.strictEqual(
+ logRecord.observedTimeUnixNano,
+ '1680253513123241728',
+ 'observedTimeUnixNano is wrong'
+ );
+ assert.strictEqual(
+ logRecord.severityNumber,
+ 'SEVERITY_NUMBER_ERROR',
+ 'severityNumber is wrong'
+ );
+ assert.strictEqual(logRecord.severityText, 'error', 'severityText is wrong');
+ assert.strictEqual(
+ logRecord.droppedAttributesCount,
+ 0,
+ 'droppedAttributesCount is wrong'
+ );
+ assert.strictEqual(logRecord.flags, TraceFlags.SAMPLED, 'flags is wrong');
+}
+
+export function ensureResourceIsCorrect(resource: IResource) {
+ assert.deepStrictEqual(resource, {
+ attributes: [
+ {
+ key: 'service.name',
+ value: {
+ stringValue: `unknown_service:${process.argv0}`,
+ value: 'stringValue',
+ },
+ },
+ {
+ key: 'telemetry.sdk.language',
+ value: {
+ stringValue: 'nodejs',
+ value: 'stringValue',
+ },
+ },
+ {
+ key: 'telemetry.sdk.name',
+ value: {
+ stringValue: 'opentelemetry',
+ value: 'stringValue',
+ },
+ },
+ {
+ key: 'telemetry.sdk.version',
+ value: {
+ stringValue: VERSION,
+ value: 'stringValue',
+ },
+ },
+ {
+ key: 'resource-attribute',
+ value: {
+ stringValue: 'some resource-attr value',
+ value: 'stringValue',
+ },
+ },
+ ],
+ droppedAttributesCount: 0,
+ });
+}
+
+export function ensureExportLogsServiceRequestIsSet(
+ json: IExportLogsServiceRequest
+) {
+ const resourceLogs = json.resourceLogs;
+ assert.strictEqual(resourceLogs?.length, 1, 'resourceLogs is missing');
+
+ const resource = resourceLogs?.[0].resource;
+ assert.ok(resource, 'resource is missing');
+
+ const scopeLogs = resourceLogs?.[0].scopeLogs;
+ assert.strictEqual(scopeLogs?.length, 1, 'scopeLogs is missing');
+
+ const scope = scopeLogs?.[0].scope;
+ assert.ok(scope, 'scope is missing');
+
+ const logRecords = scopeLogs?.[0].logRecords;
+ assert.strictEqual(logRecords?.length, 1, 'logs are missing');
+}
+
+export class MockedResponse extends Stream {
+ constructor(private _code: number, private _msg?: string) {
+ super();
+ }
+
+ send(data: string) {
+ this.emit('data', data);
+ this.emit('end');
+ }
+
+ get statusCode() {
+ return this._code;
+ }
+
+ get statusMessage() {
+ return this._msg;
+ }
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/test/node/OTLPLogsExporter.test.ts b/experimental/packages/exporter-logs-otlp-proto/test/node/OTLPLogsExporter.test.ts
new file mode 100644
index 0000000000..994a2f0ea4
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/test/node/OTLPLogsExporter.test.ts
@@ -0,0 +1,416 @@
+/*
+ * 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 { diag } from '@opentelemetry/api';
+import { ExportResultCode } from '@opentelemetry/core';
+import * as assert from 'assert';
+import * as http from 'http';
+import * as sinon from 'sinon';
+import { Stream, PassThrough } from 'stream';
+import * as zlib from 'zlib';
+import { OTLPLogsExporter } from '../../src';
+import {
+ ensureExportLogsServiceRequestIsSet,
+ ensureExportedLogRecordIsCorrect,
+ mockedReadableLogRecord,
+ MockedResponse,
+} from '../logHelper';
+import {
+ CompressionAlgorithm,
+ OTLPExporterNodeConfigBase,
+ OTLPExporterError,
+} from '@opentelemetry/otlp-exporter-base';
+import {
+ getExportRequestProto,
+ ServiceClientType,
+} from '@opentelemetry/otlp-proto-exporter-base';
+import { IExportLogsServiceRequest } from '@opentelemetry/otlp-transformer';
+import { ReadableLogRecord } from '@opentelemetry/sdk-logs';
+
+let fakeRequest: PassThrough;
+
+describe('OTLPLogsExporter - node with proto over http', () => {
+ let collectorExporter: OTLPLogsExporter;
+ let collectorExporterConfig: OTLPExporterNodeConfigBase;
+ let logs: ReadableLogRecord[];
+
+ afterEach(() => {
+ fakeRequest = new Stream.PassThrough();
+ sinon.restore();
+ });
+
+ describe('when configuring via environment', () => {
+ const envSource = process.env;
+ it('should use url defined in env that ends with root path and append version and signal path', () => {
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar/';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ `${envSource.OTEL_EXPORTER_OTLP_ENDPOINT}v1/logs`
+ );
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+ });
+ it('should use url defined in env without checking if path is already present', () => {
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar/v1/logs';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ `${envSource.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/logs`
+ );
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+ });
+ it('should use url defined in env and append version and signal', () => {
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ `${envSource.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/logs`
+ );
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+ });
+ it('should override global exporter url with signal url defined in env', () => {
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar/';
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.logs/';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
+ );
+ envSource.OTEL_EXPORTER_OTLP_ENDPOINT = '';
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ });
+ it('should add root path when signal url defined in env contains no path and no root path', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}/`
+ );
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ });
+ it('should not add root path when signal url defined in env contains root path but no path', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar/';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}`
+ );
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ });
+ it('should not add root path when signal url defined in env contains path', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar/v1/logs';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}`
+ );
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ });
+ it('should not add root path when signal url defined in env contains path and ends in /', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = 'http://foo.bar/v1/logs/';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(
+ collectorExporter.url,
+ `${envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}`
+ );
+ envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT = '';
+ });
+ it('should use headers defined via env', () => {
+ envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=bar';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(collectorExporter.headers.foo, 'bar');
+ envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
+ });
+ it('should override global headers config with signal headers defined via env', () => {
+ envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo';
+ envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=boo';
+ const collectorExporter = new OTLPLogsExporter();
+ assert.strictEqual(collectorExporter.headers.foo, 'boo');
+ assert.strictEqual(collectorExporter.headers.bar, 'foo');
+ envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = '';
+ envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
+ });
+ });
+
+ describe('export', () => {
+ beforeEach(() => {
+ collectorExporterConfig = {
+ headers: {
+ foo: 'bar',
+ },
+ hostname: 'foo',
+ url: 'http://foo.bar.com',
+ keepAlive: true,
+ httpAgentOptions: { keepAliveMsecs: 2000 },
+ };
+ collectorExporter = new OTLPLogsExporter(collectorExporterConfig);
+ logs = [];
+ logs.push(Object.assign({}, mockedReadableLogRecord));
+ });
+ afterEach(() => {
+ sinon.restore();
+ });
+
+ it('should open the connection', done => {
+ collectorExporter.export(logs, () => {});
+
+ sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
+ assert.strictEqual(options.hostname, 'foo.bar.com');
+ assert.strictEqual(options.method, 'POST');
+ assert.strictEqual(options.path, '/');
+
+ const mockRes = new MockedResponse(200);
+ cb(mockRes);
+ mockRes.send('success');
+ done();
+ return fakeRequest as any;
+ });
+ });
+
+ it('should set custom headers', done => {
+ collectorExporter.export(logs, () => {});
+
+ sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
+ assert.strictEqual(options.headers['foo'], 'bar');
+
+ const mockRes = new MockedResponse(200);
+ cb(mockRes);
+ mockRes.send('success');
+ done();
+ return fakeRequest as any;
+ });
+ });
+
+ it('should have keep alive and keepAliveMsecs option set', done => {
+ collectorExporter.export(logs, () => {});
+
+ sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
+ assert.strictEqual(options.agent.keepAlive, true);
+ assert.strictEqual(options.agent.options.keepAliveMsecs, 2000);
+
+ const mockRes = new MockedResponse(200);
+ cb(mockRes);
+ mockRes.send('success');
+ done();
+ return fakeRequest as any;
+ });
+ });
+
+ it('should successfully send the logs', done => {
+ const fakeRequest = new Stream.PassThrough();
+ sinon.stub(http, 'request').returns(fakeRequest as any);
+
+ let buff = Buffer.from('');
+ fakeRequest.on('end', () => {
+ const ExportLogsServiceRequestProto = getExportRequestProto(
+ ServiceClientType.LOGS
+ );
+ const data = ExportLogsServiceRequestProto.decode(buff);
+ const json = data?.toJSON() as IExportLogsServiceRequest;
+ const log1 = json.resourceLogs?.[0].scopeLogs?.[0].logRecords?.[0];
+ assert.ok(typeof log1 !== 'undefined', "log doesn't exist");
+ ensureExportedLogRecordIsCorrect(log1);
+
+ ensureExportLogsServiceRequestIsSet(json);
+
+ done();
+ });
+
+ fakeRequest.on('data', chunk => {
+ buff = Buffer.concat([buff, chunk]);
+ });
+
+ const clock = sinon.useFakeTimers();
+ collectorExporter.export(logs, () => {});
+ clock.tick(200);
+ clock.restore();
+ });
+
+ it('should log the successful message', done => {
+ // Need to stub/spy on the underlying logger as the "diag" instance is global
+ const spyLoggerError = sinon.stub(diag, 'error');
+
+ collectorExporter.export(logs, result => {
+ assert.strictEqual(result.code, ExportResultCode.SUCCESS);
+ assert.strictEqual(spyLoggerError.args.length, 0);
+ done();
+ });
+
+ sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
+ const mockRes = new MockedResponse(200);
+ cb(mockRes);
+ mockRes.send('success');
+ return fakeRequest as any;
+ });
+ });
+
+ it('should log the error message', done => {
+ collectorExporter.export(logs, result => {
+ assert.strictEqual(result.code, ExportResultCode.FAILED);
+ // @ts-expect-error verify error code
+ assert.strictEqual(result.error.code, 400);
+ done();
+ });
+
+ sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
+ const mockResError = new MockedResponse(400);
+ cb(mockResError);
+ mockResError.send('failed');
+
+ return fakeRequest as any;
+ });
+ });
+ });
+ describe('export - with compression', () => {
+ beforeEach(() => {
+ collectorExporterConfig = {
+ headers: {
+ foo: 'bar',
+ },
+ hostname: 'foo',
+ url: 'http://foo.bar.com',
+ keepAlive: true,
+ compression: CompressionAlgorithm.GZIP,
+ httpAgentOptions: { keepAliveMsecs: 2000 },
+ };
+ collectorExporter = new OTLPLogsExporter(collectorExporterConfig);
+ logs = [];
+ logs.push(Object.assign({}, mockedReadableLogRecord));
+ });
+ afterEach(() => {
+ sinon.restore();
+ });
+
+ it('should successfully send the logs', done => {
+ const fakeRequest = new Stream.PassThrough();
+ sinon.stub(http, 'request').returns(fakeRequest as any);
+ const spySetHeader = sinon.spy();
+ (fakeRequest as any).setHeader = spySetHeader;
+
+ let buff = Buffer.from('');
+ fakeRequest.on('end', () => {
+ const unzippedBuff = zlib.gunzipSync(buff);
+ const ExportLogsServiceRequestProto = getExportRequestProto(
+ ServiceClientType.LOGS
+ );
+ const data = ExportLogsServiceRequestProto.decode(unzippedBuff);
+ const json = data?.toJSON() as IExportLogsServiceRequest;
+ const log1 = json.resourceLogs?.[0].scopeLogs?.[0].logRecords?.[0];
+ assert.ok(typeof log1 !== 'undefined', "log doesn't exist");
+ ensureExportedLogRecordIsCorrect(log1);
+
+ ensureExportLogsServiceRequestIsSet(json);
+ assert.ok(spySetHeader.calledWith('Content-Encoding', 'gzip'));
+
+ done();
+ });
+
+ fakeRequest.on('data', chunk => {
+ buff = Buffer.concat([buff, chunk]);
+ });
+
+ const clock = sinon.useFakeTimers();
+ collectorExporter.export(logs, () => {});
+ clock.tick(200);
+ clock.restore();
+ });
+ });
+});
+
+describe('export - real http request destroyed before response received', () => {
+ let collectorExporter: OTLPLogsExporter;
+ let collectorExporterConfig: OTLPExporterNodeConfigBase;
+ let logs: ReadableLogRecord[];
+ const server = http.createServer((_, res) => {
+ setTimeout(() => {
+ res.statusCode = 200;
+ res.end();
+ }, 200);
+ });
+ before(done => {
+ server.listen(8082, done);
+ });
+ after(done => {
+ server.close(done);
+ });
+ it('should log the timeout request error message when timeout is 1', done => {
+ collectorExporterConfig = {
+ url: 'http://localhost:8082',
+ timeoutMillis: 1,
+ };
+ collectorExporter = new OTLPLogsExporter(collectorExporterConfig);
+ logs = [];
+ logs.push(Object.assign({}, mockedReadableLogRecord));
+
+ collectorExporter.export(logs, result => {
+ assert.strictEqual(result.code, ExportResultCode.FAILED);
+ const error = result.error as OTLPExporterError;
+ assert.ok(error !== undefined);
+ assert.strictEqual(error.message, 'Request Timeout');
+ done();
+ });
+ });
+ it('should log the timeout request error message when timeout is 100', done => {
+ collectorExporterConfig = {
+ url: 'http://localhost:8082',
+ timeoutMillis: 100,
+ };
+ collectorExporter = new OTLPLogsExporter(collectorExporterConfig);
+ logs = [];
+ logs.push(Object.assign({}, mockedReadableLogRecord));
+
+ collectorExporter.export(logs, result => {
+ assert.strictEqual(result.code, ExportResultCode.FAILED);
+ const error = result.error as OTLPExporterError;
+ assert.ok(error !== undefined);
+ assert.strictEqual(error.message, 'Request Timeout');
+ done();
+ });
+ });
+});
+
+describe('export - real http request destroyed after response received', () => {
+ let collectorExporter: OTLPLogsExporter;
+ let collectorExporterConfig: OTLPExporterNodeConfigBase;
+ let logs: ReadableLogRecord[];
+
+ const server = http.createServer((_, res) => {
+ res.write('writing something');
+ });
+ before(done => {
+ server.listen(8082, done);
+ });
+ after(done => {
+ server.close(done);
+ });
+ it('should log the timeout request error message', done => {
+ collectorExporterConfig = {
+ url: 'http://localhost:8082',
+ timeoutMillis: 300,
+ };
+ collectorExporter = new OTLPLogsExporter(collectorExporterConfig);
+ logs = [];
+ logs.push(Object.assign({}, mockedReadableLogRecord));
+
+ collectorExporter.export(logs, result => {
+ assert.strictEqual(result.code, ExportResultCode.FAILED);
+ const error = result.error as OTLPExporterError;
+ assert.ok(error !== undefined);
+ assert.strictEqual(error.message, 'Request Timeout');
+ done();
+ });
+ });
+});
diff --git a/experimental/packages/exporter-logs-otlp-proto/tsconfig.esm.json b/experimental/packages/exporter-logs-otlp-proto/tsconfig.esm.json
new file mode 100644
index 0000000000..5eba4694be
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/tsconfig.esm.json
@@ -0,0 +1,40 @@
+{
+ "extends": "../../../tsconfig.base.esm.json",
+ "compilerOptions": {
+ "outDir": "build/esm",
+ "rootDir": "src",
+ "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo"
+ },
+ "include": [
+ "src/**/*.ts"
+ ],
+ "references": [
+ {
+ "path": "../../../api"
+ },
+ {
+ "path": "../../../packages/opentelemetry-core"
+ },
+ {
+ "path": "../../../packages/opentelemetry-resources"
+ },
+ {
+ "path": "../../../packages/opentelemetry-sdk-trace-base"
+ },
+ {
+ "path": "../api-logs"
+ },
+ {
+ "path": "../otlp-exporter-base"
+ },
+ {
+ "path": "../otlp-proto-exporter-base"
+ },
+ {
+ "path": "../otlp-transformer"
+ },
+ {
+ "path": "../sdk-logs"
+ }
+ ]
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/tsconfig.esnext.json b/experimental/packages/exporter-logs-otlp-proto/tsconfig.esnext.json
new file mode 100644
index 0000000000..b37520a70f
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/tsconfig.esnext.json
@@ -0,0 +1,40 @@
+{
+ "extends": "../../../tsconfig.base.esnext.json",
+ "compilerOptions": {
+ "outDir": "build/esnext",
+ "rootDir": "src",
+ "tsBuildInfoFile": "build/esnext/tsconfig.esnext.tsbuildinfo"
+ },
+ "include": [
+ "src/**/*.ts"
+ ],
+ "references": [
+ {
+ "path": "../../../api"
+ },
+ {
+ "path": "../../../packages/opentelemetry-core"
+ },
+ {
+ "path": "../../../packages/opentelemetry-resources"
+ },
+ {
+ "path": "../../../packages/opentelemetry-sdk-trace-base"
+ },
+ {
+ "path": "../api-logs"
+ },
+ {
+ "path": "../otlp-exporter-base"
+ },
+ {
+ "path": "../otlp-proto-exporter-base"
+ },
+ {
+ "path": "../otlp-transformer"
+ },
+ {
+ "path": "../sdk-logs"
+ }
+ ]
+}
diff --git a/experimental/packages/exporter-logs-otlp-proto/tsconfig.json b/experimental/packages/exporter-logs-otlp-proto/tsconfig.json
new file mode 100644
index 0000000000..2349f8706c
--- /dev/null
+++ b/experimental/packages/exporter-logs-otlp-proto/tsconfig.json
@@ -0,0 +1,40 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "build",
+ "rootDir": "."
+ },
+ "include": [
+ "src/**/*.ts",
+ "test/**/*.ts"
+ ],
+ "references": [
+ {
+ "path": "../../../api"
+ },
+ {
+ "path": "../../../packages/opentelemetry-core"
+ },
+ {
+ "path": "../../../packages/opentelemetry-resources"
+ },
+ {
+ "path": "../../../packages/opentelemetry-sdk-trace-base"
+ },
+ {
+ "path": "../api-logs"
+ },
+ {
+ "path": "../otlp-exporter-base"
+ },
+ {
+ "path": "../otlp-proto-exporter-base"
+ },
+ {
+ "path": "../otlp-transformer"
+ },
+ {
+ "path": "../sdk-logs"
+ }
+ ]
+}
diff --git a/experimental/packages/exporter-trace-otlp-grpc/package.json b/experimental/packages/exporter-trace-otlp-grpc/package.json
index 62d71a5124..506bf706e8 100644
--- a/experimental/packages/exporter-trace-otlp-grpc/package.json
+++ b/experimental/packages/exporter-trace-otlp-grpc/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-trace-otlp-grpc",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Collector Exporter allows user to send collected traces to the OpenTelemetry Collector",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -50,7 +50,7 @@
"@babel/core": "7.16.0",
"@grpc/proto-loader": "^0.7.3",
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/otlp-exporter-base": "0.38.0",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/sinon": "10.0.13",
@@ -68,11 +68,11 @@
},
"dependencies": {
"@grpc/grpc-js": "^1.7.1",
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/otlp-grpc-exporter-base": "0.38.0",
- "@opentelemetry/otlp-transformer": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/otlp-grpc-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/exporter-trace-otlp-grpc",
"sideEffects": false
diff --git a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts
index 2cc5abcb2e..c99826a176 100644
--- a/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts
+++ b/experimental/packages/exporter-trace-otlp-grpc/src/OTLPTraceExporter.ts
@@ -28,6 +28,11 @@ import {
createExportTraceServiceRequest,
IExportTraceServiceRequest,
} from '@opentelemetry/otlp-transformer';
+import { VERSION } from './version';
+
+const USER_AGENT = {
+ 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
+};
/**
* OTLP Trace Exporter for Node
@@ -38,9 +43,12 @@ export class OTLPTraceExporter
{
constructor(config: OTLPGRPCExporterConfigNode = {}) {
super(config);
- const headers = baggageUtils.parseKeyPairsIntoRecord(
- getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS
- );
+ const headers = {
+ ...USER_AGENT,
+ ...baggageUtils.parseKeyPairsIntoRecord(
+ getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS
+ ),
+ };
this.metadata ||= new Metadata();
for (const [k, v] of Object.entries(headers)) {
this.metadata.set(k, v);
diff --git a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts
index 29c080b966..17e5511010 100644
--- a/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts
+++ b/experimental/packages/exporter-trace-otlp-grpc/test/OTLPTraceExporter.test.ts
@@ -27,6 +27,7 @@ import * as grpc from '@grpc/grpc-js';
import * as path from 'path';
import * as sinon from 'sinon';
import { OTLPTraceExporter } from '../src';
+import { VERSION } from '../src/version';
import {
ensureExportedSpanIsCorrect,
@@ -336,6 +337,12 @@ describe('when configuring via environment', () => {
assert.deepStrictEqual(collectorExporter.metadata?.get('foo'), ['bar']);
envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
});
+ it('should include user agent in header', () => {
+ const collectorExporter = new OTLPTraceExporter();
+ assert.deepStrictEqual(collectorExporter.metadata?.get('User-Agent'), [
+ `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
+ ]);
+ });
it('should override global headers config with signal headers defined via env', () => {
const metadata = new grpc.Metadata();
metadata.set('foo', 'bar');
diff --git a/experimental/packages/exporter-trace-otlp-http/package.json b/experimental/packages/exporter-trace-otlp-http/package.json
index 72cb324a81..2910830372 100644
--- a/experimental/packages/exporter-trace-otlp-http/package.json
+++ b/experimental/packages/exporter-trace-otlp-http/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-trace-otlp-http",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Collector Trace Exporter allows user to send collected traces to the OpenTelemetry Collector",
"main": "build/src/index.js",
"module": "build/esm/index.js",
@@ -94,11 +94,11 @@
"@opentelemetry/api": "^1.0.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/otlp-exporter-base": "0.38.0",
- "@opentelemetry/otlp-transformer": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/exporter-trace-otlp-http",
"sideEffects": false
diff --git a/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts
index 8704baf576..f10fbd0ec0 100644
--- a/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts
+++ b/experimental/packages/exporter-trace-otlp-http/src/platform/node/OTLPTraceExporter.ts
@@ -26,9 +26,13 @@ import {
createExportTraceServiceRequest,
IExportTraceServiceRequest,
} from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../../version';
const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/traces';
const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
+const USER_AGENT = {
+ 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
+};
/**
* Collector Trace Exporter for Node
@@ -39,12 +43,13 @@ export class OTLPTraceExporter
{
constructor(config: OTLPExporterNodeConfigBase = {}) {
super(config);
- this.headers = Object.assign(
- this.headers,
- baggageUtils.parseKeyPairsIntoRecord(
+ this.headers = {
+ ...this.headers,
+ ...USER_AGENT,
+ ...baggageUtils.parseKeyPairsIntoRecord(
getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS
- )
- );
+ ),
+ };
}
convert(spans: ReadableSpan[]): IExportTraceServiceRequest {
diff --git a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts
index 426aed4431..9238260d30 100644
--- a/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts
+++ b/experimental/packages/exporter-trace-otlp-http/test/node/CollectorTraceExporter.test.ts
@@ -36,6 +36,7 @@ import {
import { nextTick } from 'process';
import { MockedResponse } from './nodeHelpers';
import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../../src/version';
let fakeRequest: PassThrough;
@@ -160,6 +161,13 @@ describe('OTLPTraceExporter - node with json over http', () => {
assert.strictEqual(collectorExporter.headers.foo, 'bar');
envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
});
+ it('should include user agent in header', () => {
+ const collectorExporter = new OTLPTraceExporter();
+ assert.strictEqual(
+ collectorExporter.headers['User-Agent'],
+ `OTel-OTLP-Exporter-JavaScript/${VERSION}`
+ );
+ });
it('should override global headers config with signal headers defined via env', () => {
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo';
envSource.OTEL_EXPORTER_OTLP_TRACES_HEADERS = 'foo=boo';
diff --git a/experimental/packages/exporter-trace-otlp-proto/package.json b/experimental/packages/exporter-trace-otlp-proto/package.json
index 10fb854c80..bfe610b4d2 100644
--- a/experimental/packages/exporter-trace-otlp-proto/package.json
+++ b/experimental/packages/exporter-trace-otlp-proto/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-trace-otlp-proto",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Collector Exporter allows user to send collected traces to the OpenTelemetry Collector using protobuf over HTTP",
"main": "build/src/index.js",
"module": "build/esm/index.js",
@@ -80,12 +80,12 @@
"@opentelemetry/api": "^1.0.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/otlp-exporter-base": "0.38.0",
- "@opentelemetry/otlp-proto-exporter-base": "0.38.0",
- "@opentelemetry/otlp-transformer": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-proto-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/exporter-trace-otlp-proto",
"sideEffects": false
diff --git a/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts b/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts
index 0634013311..210a16145a 100644
--- a/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts
+++ b/experimental/packages/exporter-trace-otlp-proto/src/platform/node/OTLPTraceExporter.ts
@@ -29,9 +29,13 @@ import {
createExportTraceServiceRequest,
IExportTraceServiceRequest,
} from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../../version';
const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/traces';
const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
+const USER_AGENT = {
+ 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
+};
/**
* Collector Trace Exporter for Node with protobuf
@@ -42,12 +46,13 @@ export class OTLPTraceExporter
{
constructor(config: OTLPExporterNodeConfigBase = {}) {
super(config);
- this.headers = Object.assign(
- this.headers,
- baggageUtils.parseKeyPairsIntoRecord(
+ this.headers = {
+ ...this.headers,
+ ...USER_AGENT,
+ ...baggageUtils.parseKeyPairsIntoRecord(
getEnv().OTEL_EXPORTER_OTLP_TRACES_HEADERS
- )
- );
+ ),
+ };
}
convert(spans: ReadableSpan[]): IExportTraceServiceRequest {
diff --git a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts
index 64f0e40ea0..c0a604ce90 100644
--- a/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts
+++ b/experimental/packages/exporter-trace-otlp-proto/test/node/OTLPTraceExporter.test.ts
@@ -39,6 +39,7 @@ import {
ServiceClientType,
} from '@opentelemetry/otlp-proto-exporter-base';
import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../../src/version';
let fakeRequest: PassThrough;
@@ -52,6 +53,16 @@ describe('OTLPTraceExporter - node with proto over http', () => {
sinon.restore();
});
+ describe('default behavior for headers', () => {
+ const collectorExporter = new OTLPTraceExporter();
+ it('should include user agent in header', () => {
+ assert.strictEqual(
+ collectorExporter.headers['User-Agent'],
+ `OTel-OTLP-Exporter-JavaScript/${VERSION}`
+ );
+ });
+ });
+
describe('when configuring via environment', () => {
const envSource = process.env;
it('should use url defined in env that ends with root path and append version and signal path', () => {
diff --git a/experimental/packages/opentelemetry-browser-detector/package.json b/experimental/packages/opentelemetry-browser-detector/package.json
index c691be743b..fa3e4746a0 100644
--- a/experimental/packages/opentelemetry-browser-detector/package.json
+++ b/experimental/packages/opentelemetry-browser-detector/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/opentelemetry-browser-detector",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Resource Detector for Browser",
"main": "build/src/index.js",
"module": "build/esm/index.js",
@@ -70,8 +70,8 @@
"@opentelemetry/api": "^1.0.0"
},
"dependencies": {
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/browser-detector"
}
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json
index 02e86fcb46..85b92e6fcb 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-metrics-otlp-grpc",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Collector Metrics Exporter allows user to send collected metrics to the OpenTelemetry Collector",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -67,12 +67,12 @@
},
"dependencies": {
"@grpc/grpc-js": "^1.7.1",
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/exporter-metrics-otlp-http": "0.38.0",
- "@opentelemetry/otlp-grpc-exporter-base": "0.38.0",
- "@opentelemetry/otlp-transformer": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/exporter-metrics-otlp-http": "0.39.1",
+ "@opentelemetry/otlp-grpc-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc",
"sideEffects": false
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts
index 20f917e543..0ada75d437 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/src/OTLPMetricExporter.ts
@@ -32,6 +32,11 @@ import {
createExportMetricsServiceRequest,
IExportMetricsServiceRequest,
} from '@opentelemetry/otlp-transformer';
+import { VERSION } from './version';
+
+const USER_AGENT = {
+ 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
+};
class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<
ResourceMetrics,
@@ -39,9 +44,13 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<
> {
constructor(config?: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions) {
super(config);
- const headers = baggageUtils.parseKeyPairsIntoRecord(
- getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS
- );
+ const headers = {
+ ...USER_AGENT,
+ ...baggageUtils.parseKeyPairsIntoRecord(
+ getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS
+ ),
+ };
+
this.metadata ||= new Metadata();
for (const [k, v] of Object.entries(headers)) {
this.metadata.set(k, v);
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts
index 4b8d326545..9e4e27ecb0 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-grpc/test/OTLPMetricExporter.test.ts
@@ -43,6 +43,7 @@ import {
IExportMetricsServiceRequest,
IResourceMetrics,
} from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../src/version';
const metricsServiceProtoPath =
'opentelemetry/proto/collector/metrics/v1/metrics_service.proto';
@@ -314,6 +315,13 @@ describe('when configuring via environment', () => {
);
envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
});
+ it('should include user agent in header', () => {
+ const collectorExporter = new OTLPMetricExporter();
+ assert.deepStrictEqual(
+ collectorExporter._otlpExporter.metadata?.get('User-Agent'),
+ [`OTel-OTLP-Exporter-JavaScript/${VERSION}`]
+ );
+ });
it('should override global headers config with signal headers defined via env', () => {
const metadata = new grpc.Metadata();
metadata.set('foo', 'bar');
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json
index 8230989634..7ddbd94874 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-metrics-otlp-http",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Collector Metrics Exporter allows user to send collected metrics to the OpenTelemetry Collector",
"main": "build/src/index.js",
"module": "build/esm/index.js",
@@ -93,11 +93,11 @@
"@opentelemetry/api": "^1.3.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/otlp-exporter-base": "0.38.0",
- "@opentelemetry/otlp-transformer": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-metrics-otlp-http",
"sideEffects": false
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts
index 980931a6cb..f83e414e70 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/src/platform/node/OTLPMetricExporter.ts
@@ -28,9 +28,13 @@ import {
createExportMetricsServiceRequest,
IExportMetricsServiceRequest,
} from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../../version';
const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/metrics';
const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
+const USER_AGENT = {
+ 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
+};
class OTLPExporterNodeProxy extends OTLPExporterNodeBase<
ResourceMetrics,
@@ -38,12 +42,13 @@ class OTLPExporterNodeProxy extends OTLPExporterNodeBase<
> {
constructor(config?: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions) {
super(config);
- this.headers = Object.assign(
- this.headers,
- baggageUtils.parseKeyPairsIntoRecord(
+ this.headers = {
+ ...this.headers,
+ ...USER_AGENT,
+ ...baggageUtils.parseKeyPairsIntoRecord(
getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS
- )
- );
+ ),
+ };
}
convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest {
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts
index d23ca628f7..042e5ebb4b 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-http/test/node/CollectorMetricExporter.test.ts
@@ -50,6 +50,7 @@ import {
OTLPExporterNodeConfigBase,
} from '@opentelemetry/otlp-exporter-base';
import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../../src/version';
let fakeRequest: PassThrough;
@@ -188,6 +189,13 @@ describe('OTLPMetricExporter - node with json over http', () => {
assert.strictEqual(collectorExporter._otlpExporter.headers.foo, 'bar');
envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
});
+ it('should include user agent in header', () => {
+ const collectorExporter = new OTLPMetricExporter();
+ assert.strictEqual(
+ collectorExporter._otlpExporter.headers['User-Agent'],
+ `OTel-OTLP-Exporter-JavaScript/${VERSION}`
+ );
+ });
it('should override global headers config with signal headers defined via env', () => {
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo';
envSource.OTEL_EXPORTER_OTLP_METRICS_HEADERS = 'foo=boo';
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json
index ceb2880326..d384051e56 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-metrics-otlp-proto",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Collector Metrics Exporter allows user to send collected metrics to the OpenTelemetry Collector using protobuf over HTTP",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -65,13 +65,13 @@
"@opentelemetry/api": "^1.3.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/exporter-metrics-otlp-http": "0.38.0",
- "@opentelemetry/otlp-exporter-base": "0.38.0",
- "@opentelemetry/otlp-proto-exporter-base": "0.38.0",
- "@opentelemetry/otlp-transformer": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/exporter-metrics-otlp-http": "0.39.1",
+ "@opentelemetry/otlp-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-proto-exporter-base": "0.39.1",
+ "@opentelemetry/otlp-transformer": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-metrics-otlp-proto",
"sideEffects": false
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts
index c29ae0085c..8d1fb114b3 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/src/OTLPMetricExporter.ts
@@ -31,9 +31,13 @@ import {
createExportMetricsServiceRequest,
IExportMetricsServiceRequest,
} from '@opentelemetry/otlp-transformer';
+import { VERSION } from './version';
const DEFAULT_COLLECTOR_RESOURCE_PATH = 'v1/metrics';
const DEFAULT_COLLECTOR_URL = `http://localhost:4318/${DEFAULT_COLLECTOR_RESOURCE_PATH}`;
+const USER_AGENT = {
+ 'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
+};
class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase<
ResourceMetrics,
@@ -41,12 +45,13 @@ class OTLPMetricExporterNodeProxy extends OTLPProtoExporterNodeBase<
> {
constructor(config?: OTLPExporterNodeConfigBase & OTLPMetricExporterOptions) {
super(config);
- this.headers = Object.assign(
- this.headers,
- baggageUtils.parseKeyPairsIntoRecord(
+ this.headers = {
+ ...this.headers,
+ ...USER_AGENT,
+ ...baggageUtils.parseKeyPairsIntoRecord(
getEnv().OTEL_EXPORTER_OTLP_METRICS_HEADERS
- )
- );
+ ),
+ };
}
convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest {
diff --git a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts
index 05ca183dcc..d3270b6a9f 100644
--- a/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts
+++ b/experimental/packages/opentelemetry-exporter-metrics-otlp-proto/test/OTLPMetricExporter.test.ts
@@ -46,6 +46,7 @@ import { OTLPMetricExporterOptions } from '@opentelemetry/exporter-metrics-otlp-
import { Stream, PassThrough } from 'stream';
import { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer';
+import { VERSION } from '../src/version';
let fakeRequest: PassThrough;
@@ -60,6 +61,16 @@ describe('OTLPMetricExporter - node with proto over http', () => {
sinon.restore();
});
+ describe('default behavior for headers', () => {
+ const collectorExporter = new OTLPMetricExporter();
+ it('should include user agent in header', () => {
+ assert.strictEqual(
+ collectorExporter._otlpExporter.headers['User-Agent'],
+ `OTel-OTLP-Exporter-JavaScript/${VERSION}`
+ );
+ });
+ });
+
describe('when configuring via environment', () => {
const envSource = process.env;
it('should use url defined in env that ends with root path and append version and signal path', () => {
diff --git a/experimental/packages/opentelemetry-exporter-prometheus/package.json b/experimental/packages/opentelemetry-exporter-prometheus/package.json
index be79a2b2e5..144c4e62d8 100644
--- a/experimental/packages/opentelemetry-exporter-prometheus/package.json
+++ b/experimental/packages/opentelemetry-exporter-prometheus/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/exporter-prometheus",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry Exporter Prometheus provides a metrics endpoint for Prometheus",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -44,7 +44,7 @@
},
"devDependencies": {
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/semantic-conventions": "1.12.0",
+ "@opentelemetry/semantic-conventions": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/sinon": "10.0.13",
@@ -59,9 +59,9 @@
"@opentelemetry/api": "^1.3.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-prometheus",
"sideEffects": false
diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/package.json b/experimental/packages/opentelemetry-instrumentation-fetch/package.json
index e192e4b602..29479c7c8f 100644
--- a/experimental/packages/opentelemetry-instrumentation-fetch/package.json
+++ b/experimental/packages/opentelemetry-instrumentation-fetch/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/instrumentation-fetch",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry fetch automatic instrumentation package.",
"main": "build/src/index.js",
"module": "build/esm/index.js",
@@ -56,9 +56,9 @@
"devDependencies": {
"@babel/core": "7.16.0",
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/context-zone": "1.12.0",
- "@opentelemetry/propagator-b3": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
+ "@opentelemetry/context-zone": "1.13.0",
+ "@opentelemetry/propagator-b3": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/sinon": "10.0.13",
@@ -86,10 +86,10 @@
"@opentelemetry/api": "^1.0.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/instrumentation": "0.38.0",
- "@opentelemetry/sdk-trace-web": "1.12.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/sdk-trace-web": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-fetch",
"sideEffects": false
diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts b/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts
index 40f3381dbb..318e0f98c3 100644
--- a/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts
+++ b/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts
@@ -49,6 +49,10 @@ class DummySpanExporter implements tracing.SpanExporter {
shutdown() {
return Promise.resolve();
}
+
+ forceFlush(): Promise {
+ return Promise.resolve();
+ }
}
const getData = (url: string, method?: string) => {
diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/package.json b/experimental/packages/opentelemetry-instrumentation-grpc/package.json
index 5166c08fae..1e63a6dd06 100644
--- a/experimental/packages/opentelemetry-instrumentation-grpc/package.json
+++ b/experimental/packages/opentelemetry-instrumentation-grpc/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/instrumentation-grpc",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry grpc automatic instrumentation package.",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -18,7 +18,8 @@
"watch": "tsc --build --watch",
"precompile": "lerna run version --scope $(npm pkg get name) --include-dependencies",
"prewatch": "node ../../../scripts/version-update.js",
- "peer-api-check": "node ../../../scripts/peer-api-check.js"
+ "peer-api-check": "node ../../../scripts/peer-api-check.js",
+ "postinstall": "node -e \"console.log(\\\"\\x1b[95m%s\\x1b[0m\\\", \\\"@opentelemetry/instrumentation-grpc - warning: The package 'grpc' (https://www.npmjs.com/package/grpc) is deprecated. It will no longer be instrumented in the next release of '@opentelemetry/instrumentation-grpc'. Please migrate to '@grpc/grpc-js' (https://www.npmjs.com/package/@grpc/grpc-js) to continue receiving telemetry.\\\");\""
},
"keywords": [
"opentelemetry",
@@ -48,10 +49,10 @@
"@grpc/grpc-js": "^1.7.1",
"@grpc/proto-loader": "^0.7.3",
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/context-async-hooks": "1.12.0",
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
- "@opentelemetry/sdk-trace-node": "1.12.0",
+ "@opentelemetry/context-async-hooks": "1.13.0",
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/sdk-trace-node": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/semver": "7.3.9",
@@ -70,8 +71,8 @@
"@opentelemetry/api": "^1.3.0"
},
"dependencies": {
- "@opentelemetry/instrumentation": "0.38.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-grpc",
"sideEffects": false
diff --git a/experimental/packages/opentelemetry-instrumentation-http/package.json b/experimental/packages/opentelemetry-instrumentation-http/package.json
index a2e7604109..b46eef6a18 100644
--- a/experimental/packages/opentelemetry-instrumentation-http/package.json
+++ b/experimental/packages/opentelemetry-instrumentation-http/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/instrumentation-http",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry http/https automatic instrumentation package.",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -46,17 +46,17 @@
},
"devDependencies": {
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/context-async-hooks": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
- "@opentelemetry/sdk-trace-node": "1.12.0",
+ "@opentelemetry/context-async-hooks": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/sdk-trace-node": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/request-promise-native": "1.0.18",
"@types/semver": "7.3.9",
"@types/sinon": "10.0.13",
"@types/superagent": "4.1.13",
- "axios": "0.24.0",
+ "axios": "1.4.0",
"codecov": "3.8.3",
"mocha": "10.0.0",
"nock": "13.0.11",
@@ -72,9 +72,9 @@
"@opentelemetry/api": "^1.3.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/instrumentation": "0.38.0",
- "@opentelemetry/semantic-conventions": "1.12.0",
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/semantic-conventions": "1.13.0",
"semver": "^7.3.5"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-http",
diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts
index 0b5c166dd5..15ca92a45e 100644
--- a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts
+++ b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts
@@ -66,7 +66,6 @@ import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
export class HttpInstrumentation extends InstrumentationBase {
/** keep track on spans not ended */
private readonly _spanNotEnded: WeakSet = new WeakSet();
- private readonly _version = process.versions.node;
private _headerCapture;
private _httpServerDurationHistogram!: Histogram;
private _httpClientDurationHistogram!: Histogram;
@@ -112,11 +111,12 @@ export class HttpInstrumentation extends InstrumentationBase {
}
private _getHttpInstrumentation() {
+ const version = process.versions.node;
return new InstrumentationNodeModuleDefinition(
'http',
['*'],
moduleExports => {
- this._diag.debug(`Applying patch for http@${this._version}`);
+ this._diag.debug(`Applying patch for http@${version}`);
if (isWrapped(moduleExports.request)) {
this._unwrap(moduleExports, 'request');
}
@@ -145,7 +145,7 @@ export class HttpInstrumentation extends InstrumentationBase {
},
moduleExports => {
if (moduleExports === undefined) return;
- this._diag.debug(`Removing patch for http@${this._version}`);
+ this._diag.debug(`Removing patch for http@${version}`);
this._unwrap(moduleExports, 'request');
this._unwrap(moduleExports, 'get');
@@ -155,11 +155,12 @@ export class HttpInstrumentation extends InstrumentationBase {
}
private _getHttpsInstrumentation() {
+ const version = process.versions.node;
return new InstrumentationNodeModuleDefinition(
'https',
['*'],
moduleExports => {
- this._diag.debug(`Applying patch for https@${this._version}`);
+ this._diag.debug(`Applying patch for https@${version}`);
if (isWrapped(moduleExports.request)) {
this._unwrap(moduleExports, 'request');
}
@@ -188,7 +189,7 @@ export class HttpInstrumentation extends InstrumentationBase {
},
moduleExports => {
if (moduleExports === undefined) return;
- this._diag.debug(`Removing patch for https@${this._version}`);
+ this._diag.debug(`Removing patch for https@${version}`);
this._unwrap(moduleExports, 'request');
this._unwrap(moduleExports, 'get');
diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-package.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-package.test.ts
index 39b288ccdb..c07039f290 100644
--- a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-package.test.ts
+++ b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-package.test.ts
@@ -104,7 +104,7 @@ describe('Packages', () => {
const result = await httpPackage.get(urlparsed.href!);
if (!resHeaders) {
const res = result as AxiosResponse;
- resHeaders = res.headers;
+ resHeaders = res.headers as any;
}
const spans = memoryExporter.getFinishedSpans();
const span = spans[0];
diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts
index dada803e45..a7c5972a6a 100644
--- a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts
+++ b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/https-package.test.ts
@@ -110,7 +110,7 @@ describe('Packages', () => {
const result = await httpPackage.get(urlparsed.href!);
if (!resHeaders) {
const res = result as AxiosResponse;
- resHeaders = res.headers;
+ resHeaders = res.headers as any;
}
const spans = memoryExporter.getFinishedSpans();
const span = spans[0];
diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json
index 67607dacfa..4bf5707caf 100644
--- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json
+++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/instrumentation-xml-http-request",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry XMLHttpRequest automatic instrumentation package.",
"main": "build/src/index.js",
"module": "build/esm/index.js",
@@ -56,9 +56,9 @@
"devDependencies": {
"@babel/core": "7.16.0",
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/context-zone": "1.12.0",
- "@opentelemetry/propagator-b3": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
+ "@opentelemetry/context-zone": "1.13.0",
+ "@opentelemetry/propagator-b3": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/sinon": "10.0.13",
@@ -86,10 +86,10 @@
"@opentelemetry/api": "^1.0.0"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/instrumentation": "0.38.0",
- "@opentelemetry/sdk-trace-web": "1.12.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/sdk-trace-web": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-xml-http-request",
"sideEffects": false
diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts b/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts
index 6176dd005c..b304bb9c03 100644
--- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts
+++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/test/xhr.test.ts
@@ -46,6 +46,10 @@ class DummySpanExporter implements tracing.SpanExporter {
shutdown() {
return Promise.resolve();
}
+
+ forceFlush(): Promise {
+ return Promise.resolve();
+ }
}
const XHR_TIMEOUT = 2000;
diff --git a/experimental/packages/opentelemetry-instrumentation/README.md b/experimental/packages/opentelemetry-instrumentation/README.md
index 682fc5741a..6c27e3d36d 100644
--- a/experimental/packages/opentelemetry-instrumentation/README.md
+++ b/experimental/packages/opentelemetry-instrumentation/README.md
@@ -219,12 +219,18 @@ If nothing is specified the global registered provider is used. Usually this is
There might be usecase where someone has the need for more providers within an application. Please note that special care must be takes in such setups
to avoid leaking information from one provider to the other because there are a lot places where e.g. the global `ContextManager` or `Propagator` is used.
+## Instrumentation for ES Modules In NodeJS (experimental)
+
+As the module loading mechanism for ESM is different than CJS, you need to select a custom loader so instrumentation can load hook on the esm module it want to patch. To do so, you must provide the `--experimental-loader=@opentelemetry/instrumentation/hook.mjs` flag to the `node` binary. Alternatively you can set the `NODE_OPTIONS` environment variable to `NODE_OPTIONS="--experimental-loader=@opentelemetry/instrumentation/hook.mjs"`.
+As the ESM module loader from NodeJS is experimental, so is our support for it. Feel free to provide feedback or report issues about it.
+
+**Note**: ESM Instrumentation is not yet supported for Node 20.
+
## Limitations
-Instrumentations for external modules (e.g. express, mongodb,...) hooks the `require` call. Therefore following conditions need to be met that this mechanism can work:
+Instrumentations for external modules (e.g. express, mongodb,...) hooks the `require` call or `import` statement. Therefore following conditions need to be met that this mechanism can work:
-* `require` is used. ECMA script modules (using `import`) is not supported as of now
-* Instrumentations are registered **before** the module to instrument is `require`ed
+* Instrumentations are registered **before** the module to instrument is `require`ed (CJS only)
* modules are not included in a bundle. Tools like `esbuild`, `webpack`, ... usually have some mechanism to exclude specific modules from bundling
## License
diff --git a/experimental/packages/opentelemetry-instrumentation/hook.mjs b/experimental/packages/opentelemetry-instrumentation/hook.mjs
new file mode 100644
index 0000000000..7111b37699
--- /dev/null
+++ b/experimental/packages/opentelemetry-instrumentation/hook.mjs
@@ -0,0 +1,28 @@
+/*!
+ * Copyright 2021 Datadog, Inc.
+ * 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.
+ */
+
+// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
+//
+// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
+
+import {
+ load,
+ resolve,
+ getFormat,
+ getSource,
+} from 'import-in-the-middle/hook.mjs';
+export { load, resolve, getFormat, getSource };
diff --git a/experimental/packages/opentelemetry-instrumentation/package.json b/experimental/packages/opentelemetry-instrumentation/package.json
index 266198f5c5..4164952821 100644
--- a/experimental/packages/opentelemetry-instrumentation/package.json
+++ b/experimental/packages/opentelemetry-instrumentation/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/instrumentation",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "Base class for node which OpenTelemetry instrumentation modules extend",
"author": "OpenTelemetry Authors",
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation",
@@ -32,6 +32,7 @@
"build/src/**/*.js",
"build/src/**/*.js.map",
"build/src/**/*.d.ts",
+ "hook.mjs",
"doc",
"LICENSE",
"README.md"
@@ -47,7 +48,9 @@
"tdd": "npm run tdd:node",
"tdd:node": "npm run test -- --watch-extensions ts --watch",
"tdd:browser": "karma start",
- "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'",
+ "test:cjs": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'",
+ "test:esm": "nyc node --experimental-loader=./hook.mjs ../../../node_modules/mocha/bin/mocha 'test/node/*.test.mjs' test/node/*.test.mjs",
+ "test": "npm run test:cjs && npm run test:esm",
"test:browser": "nyc karma start --single-run",
"version": "node ../../../scripts/version-update.js",
"watch": "tsc --build --watch tsconfig.json tsconfig.esm.json tsconfig.esnext.json",
@@ -68,6 +71,8 @@
"url": "https://github.com/open-telemetry/opentelemetry-js/issues"
},
"dependencies": {
+ "@types/shimmer": "^1.0.2",
+ "import-in-the-middle": "1.3.5",
"require-in-the-middle": "^7.1.0",
"semver": "^7.3.2",
"shimmer": "^1.2.1"
@@ -78,11 +83,10 @@
"devDependencies": {
"@babel/core": "7.16.0",
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/sdk-metrics": "1.12.0",
+ "@opentelemetry/sdk-metrics": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/semver": "7.3.9",
- "@types/shimmer": "1.0.2",
"@types/sinon": "10.0.13",
"@types/webpack-env": "1.16.3",
"babel-loader": "8.2.3",
diff --git a/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts b/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts
index 5790c9564e..03d8f6ba37 100644
--- a/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts
+++ b/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts
@@ -16,12 +16,16 @@
import * as types from '../../types';
import * as path from 'path';
+import { types as utilTypes } from 'util';
import { satisfies } from 'semver';
+import { wrap, unwrap, massWrap, massUnwrap } from 'shimmer';
import { InstrumentationAbstract } from '../../instrumentation';
import {
RequireInTheMiddleSingleton,
Hooked,
} from './RequireInTheMiddleSingleton';
+import type { HookFn } from 'import-in-the-middle';
+import * as ImportInTheMiddle from 'import-in-the-middle';
import { InstrumentationModuleDefinition } from './types';
import { diag } from '@opentelemetry/api';
import type { OnRequireFn } from 'require-in-the-middle';
@@ -68,6 +72,75 @@ export abstract class InstrumentationBase
}
}
+ protected override _wrap: typeof wrap = (moduleExports, name, wrapper) => {
+ if (!utilTypes.isProxy(moduleExports)) {
+ return wrap(moduleExports, name, wrapper);
+ } else {
+ const wrapped = wrap(Object.assign({}, moduleExports), name, wrapper);
+
+ return Object.defineProperty(moduleExports, name, {
+ value: wrapped,
+ });
+ }
+ };
+
+ protected override _unwrap: typeof unwrap = (moduleExports, name) => {
+ if (!utilTypes.isProxy(moduleExports)) {
+ return unwrap(moduleExports, name);
+ } else {
+ return Object.defineProperty(moduleExports, name, {
+ value: moduleExports[name],
+ });
+ }
+ };
+
+ protected override _massWrap: typeof massWrap = (
+ moduleExportsArray,
+ names,
+ wrapper
+ ) => {
+ if (!moduleExportsArray) {
+ diag.error('must provide one or more modules to patch');
+ return;
+ } else if (!Array.isArray(moduleExportsArray)) {
+ moduleExportsArray = [moduleExportsArray];
+ }
+
+ if (!(names && Array.isArray(names))) {
+ diag.error('must provide one or more functions to wrap on modules');
+ return;
+ }
+
+ moduleExportsArray.forEach(moduleExports => {
+ names.forEach(name => {
+ this._wrap(moduleExports, name, wrapper);
+ });
+ });
+ };
+
+ protected override _massUnwrap: typeof massUnwrap = (
+ moduleExportsArray,
+ names
+ ) => {
+ if (!moduleExportsArray) {
+ diag.error('must provide one or more modules to patch');
+ return;
+ } else if (!Array.isArray(moduleExportsArray)) {
+ moduleExportsArray = [moduleExportsArray];
+ }
+
+ if (!(names && Array.isArray(names))) {
+ diag.error('must provide one or more functions to wrap on modules');
+ return;
+ }
+
+ moduleExportsArray.forEach(moduleExports => {
+ names.forEach(name => {
+ this._unwrap(moduleExports, name);
+ });
+ });
+ };
+
private _warnOnPreloadedModules(): void {
this._modules.forEach((module: InstrumentationModuleDefinition) => {
const { name } = module;
@@ -101,7 +174,7 @@ export abstract class InstrumentationBase
module: InstrumentationModuleDefinition,
exports: T,
name: string,
- baseDir?: string
+ baseDir?: string | void
): T {
if (!baseDir) {
if (typeof module.patch === 'function') {
@@ -168,6 +241,14 @@ export abstract class InstrumentationBase
this._warnOnPreloadedModules();
for (const module of this._modules) {
+ const hookFn: HookFn = (exports, name, baseDir) => {
+ return this._onRequire(
+ module as unknown as InstrumentationModuleDefinition,
+ exports,
+ name,
+ baseDir
+ );
+ };
const onRequire: OnRequireFn = (exports, name, baseDir) => {
return this._onRequire(
module as unknown as InstrumentationModuleDefinition,
@@ -185,6 +266,13 @@ export abstract class InstrumentationBase
: this._requireInTheMiddleSingleton.register(module.name, onRequire);
this._hooks.push(hook);
+ const esmHook =
+ new (ImportInTheMiddle as unknown as typeof ImportInTheMiddle.default)(
+ [module.name],
+ { internals: false },
+ hookFn
+ );
+ this._hooks.push(esmHook);
}
}
diff --git a/experimental/packages/opentelemetry-instrumentation/test/node/EsmInstrumentation.test.mjs b/experimental/packages/opentelemetry-instrumentation/test/node/EsmInstrumentation.test.mjs
new file mode 100644
index 0000000000..f09097cd79
--- /dev/null
+++ b/experimental/packages/opentelemetry-instrumentation/test/node/EsmInstrumentation.test.mjs
@@ -0,0 +1,138 @@
+/*
+ * 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 {
+ InstrumentationBase,
+ InstrumentationNodeModuleDefinition,
+} from '../../build/src/index.js';
+import * as exported from 'test-esm-module';
+
+class TestInstrumentationWrapFn extends InstrumentationBase {
+ constructor(config) {
+ super('test-esm-instrumentation', '0.0.1', config);
+ }
+ init() {
+ console.log('test-esm-instrumentation initialized!');
+ return new InstrumentationNodeModuleDefinition(
+ 'test-esm-module',
+ ['*'],
+ moduleExports => {
+ this._wrap(moduleExports, 'testFunction', () => {
+ return () => 'patched';
+ });
+ return moduleExports;
+ },
+ moduleExports => {
+ this._unwrap(moduleExports, 'testFunction');
+ return moduleExports;
+ }
+ );
+ }
+}
+
+class TestInstrumentationMasswrapFn extends InstrumentationBase {
+ constructor(config) {
+ super('test-esm-instrumentation', '0.0.1', config);
+ }
+ init() {
+ console.log('test-esm-instrumentation initialized!');
+ return new InstrumentationNodeModuleDefinition(
+ 'test-esm-module',
+ ['*'],
+ moduleExports => {
+ this._massWrap(
+ [moduleExports],
+ ['testFunction', 'secondTestFunction'],
+ () => {
+ return () => 'patched';
+ }
+ );
+ return moduleExports;
+ },
+ moduleExports => {
+ this._massUnwrap(
+ [moduleExports],
+ ['testFunction', 'secondTestFunction']
+ );
+ return moduleExports;
+ }
+ );
+ }
+}
+
+class TestInstrumentationSimple extends InstrumentationBase {
+ constructor(config) {
+ super('test-esm-instrumentation', '0.0.1', config);
+ }
+ init() {
+ console.log('test-esm-instrumentation initialized!');
+ return new InstrumentationNodeModuleDefinition(
+ 'test-esm-module',
+ ['*'],
+ moduleExports => {
+ moduleExports.testConstant = 43;
+ return moduleExports;
+ }
+ );
+ }
+}
+describe('when loading esm module', () => {
+ const instrumentationWrap = new TestInstrumentationWrapFn({
+ enabled: false,
+ });
+
+ it('should patch module file directly', async () => {
+ const instrumentation = new TestInstrumentationSimple({
+ enabled: false,
+ });
+ instrumentation.enable();
+ assert.deepEqual(exported.testConstant, 43);
+ });
+
+ it('should patch a module with the wrap function', async () => {
+ instrumentationWrap.enable();
+ assert.deepEqual(exported.testFunction(), 'patched');
+ });
+
+ it('should unwrap a patched function', async () => {
+ instrumentationWrap.enable();
+ // disable to trigger unwrap
+ instrumentationWrap.disable();
+ assert.deepEqual(exported.testFunction(), 'original');
+ });
+
+ it('should wrap multiple functions with masswrap', () => {
+ const instrumentation = new TestInstrumentationMasswrapFn({
+ enabled: false,
+ });
+
+ instrumentation.enable();
+ assert.deepEqual(exported.testFunction(), 'patched');
+ assert.deepEqual(exported.secondTestFunction(), 'patched');
+ });
+
+ it('should unwrap multiple functions with massunwrap', () => {
+ const instrumentation = new TestInstrumentationMasswrapFn({
+ enabled: false,
+ });
+
+ instrumentation.enable();
+ instrumentation.disable();
+ assert.deepEqual(exported.testFunction(), 'original');
+ assert.deepEqual(exported.secondTestFunction(), 'original');
+ });
+});
diff --git a/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/.gitkeep b/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/test-esm-module/package.json b/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/test-esm-module/package.json
new file mode 100644
index 0000000000..3caeae666d
--- /dev/null
+++ b/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/test-esm-module/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "test-esm-module",
+ "version": "0.1.0",
+ "main": "./src/index.js",
+ "type": "module"
+}
diff --git a/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/test-esm-module/src/index.js b/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/test-esm-module/src/index.js
new file mode 100644
index 0000000000..2fb6c6ed25
--- /dev/null
+++ b/experimental/packages/opentelemetry-instrumentation/test/node/node_modules/test-esm-module/src/index.js
@@ -0,0 +1,9 @@
+export const testFunction = () => {
+ return 'original';
+};
+
+export const secondTestFunction = () => {
+ return 'original';
+};
+
+export const testConstant = 42;
diff --git a/experimental/packages/opentelemetry-sdk-node/package.json b/experimental/packages/opentelemetry-sdk-node/package.json
index fd4f4cc255..b6dd740713 100644
--- a/experimental/packages/opentelemetry-sdk-node/package.json
+++ b/experimental/packages/opentelemetry-sdk-node/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/sdk-node",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry SDK for Node.js",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
@@ -44,25 +44,25 @@
"access": "public"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0",
- "@opentelemetry/exporter-jaeger": "1.12.0",
- "@opentelemetry/exporter-trace-otlp-grpc": "0.38.0",
- "@opentelemetry/exporter-trace-otlp-http": "0.38.0",
- "@opentelemetry/exporter-trace-otlp-proto": "0.38.0",
- "@opentelemetry/exporter-zipkin": "1.12.0",
- "@opentelemetry/instrumentation": "0.38.0",
- "@opentelemetry/resources": "1.12.0",
- "@opentelemetry/sdk-metrics": "1.12.0",
- "@opentelemetry/sdk-trace-base": "1.12.0",
- "@opentelemetry/sdk-trace-node": "1.12.0",
- "@opentelemetry/semantic-conventions": "1.12.0"
+ "@opentelemetry/core": "1.13.0",
+ "@opentelemetry/exporter-jaeger": "1.13.0",
+ "@opentelemetry/exporter-trace-otlp-grpc": "0.39.1",
+ "@opentelemetry/exporter-trace-otlp-http": "0.39.1",
+ "@opentelemetry/exporter-trace-otlp-proto": "0.39.1",
+ "@opentelemetry/exporter-zipkin": "1.13.0",
+ "@opentelemetry/instrumentation": "0.39.1",
+ "@opentelemetry/resources": "1.13.0",
+ "@opentelemetry/sdk-metrics": "1.13.0",
+ "@opentelemetry/sdk-trace-base": "1.13.0",
+ "@opentelemetry/sdk-trace-node": "1.13.0",
+ "@opentelemetry/semantic-conventions": "1.13.0"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.3.0 <1.5.0"
},
"devDependencies": {
"@opentelemetry/api": "1.4.1",
- "@opentelemetry/context-async-hooks": "1.12.0",
+ "@opentelemetry/context-async-hooks": "1.13.0",
"@types/mocha": "10.0.0",
"@types/node": "18.6.5",
"@types/semver": "7.3.9",
diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts
index 82074719df..03efc31142 100644
--- a/experimental/packages/opentelemetry-sdk-node/src/types.ts
+++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts
@@ -17,7 +17,7 @@
import type { ContextManager } from '@opentelemetry/api';
import { TextMapPropagator } from '@opentelemetry/api';
import { InstrumentationOption } from '@opentelemetry/instrumentation';
-import { Detector, DetectorSync, Resource } from '@opentelemetry/resources';
+import { Detector, DetectorSync, IResource } from '@opentelemetry/resources';
import { MetricReader, View } from '@opentelemetry/sdk-metrics';
import {
Sampler,
@@ -34,7 +34,7 @@ export interface NodeSDKConfiguration {
metricReader: MetricReader;
views: View[];
instrumentations: InstrumentationOption[];
- resource: Resource;
+ resource: IResource;
resourceDetectors: Array;
sampler: Sampler;
serviceName?: string;
diff --git a/experimental/packages/otlp-exporter-base/package.json b/experimental/packages/otlp-exporter-base/package.json
index 4a75e6ad89..2d06e7b181 100644
--- a/experimental/packages/otlp-exporter-base/package.json
+++ b/experimental/packages/otlp-exporter-base/package.json
@@ -1,6 +1,6 @@
{
"name": "@opentelemetry/otlp-exporter-base",
- "version": "0.38.0",
+ "version": "0.39.1",
"description": "OpenTelemetry OTLP Exporter base (for internal use only)",
"main": "build/src/index.js",
"module": "build/esm/index.js",
@@ -61,7 +61,7 @@
"access": "public"
},
"dependencies": {
- "@opentelemetry/core": "1.12.0"
+ "@opentelemetry/core": "1.13.0"
},
"devDependencies": {
"@opentelemetry/api": "1.4.1",
diff --git a/experimental/packages/otlp-exporter-base/src/OTLPExporterBase.ts b/experimental/packages/otlp-exporter-base/src/OTLPExporterBase.ts
index c78adb7e27..c960305783 100644
--- a/experimental/packages/otlp-exporter-base/src/OTLPExporterBase.ts
+++ b/experimental/packages/otlp-exporter-base/src/OTLPExporterBase.ts
@@ -117,15 +117,22 @@ export abstract class OTLPExporterBase<
return this._shutdownOnce.call();
}
+ /**
+ * Exports any pending spans in the exporter
+ */
+ forceFlush(): Promise {
+ return Promise.all(this._sendingPromises).then(() => {
+ /** ignore resolved values */
+ });
+ }
+
/**
* Called by _shutdownOnce with BindOnceFuture
*/
private _shutdown(): Promise {
diag.debug('shutdown started');
this.onShutdown();
- return Promise.all(this._sendingPromises).then(() => {
- /** ignore resolved values */
- });
+ return this.forceFlush();
}
abstract onShutdown(): void;
diff --git a/experimental/packages/otlp-exporter-base/test/node/util.test.ts b/experimental/packages/otlp-exporter-base/test/node/util.test.ts
index 86c8df40ab..b279e57b9a 100644
--- a/experimental/packages/otlp-exporter-base/test/node/util.test.ts
+++ b/experimental/packages/otlp-exporter-base/test/node/util.test.ts
@@ -60,6 +60,13 @@ class Exporter extends OTLPExporterNodeBase