Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(proto): add @opentelemetry/proto package #2691

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0090664
feat(proto): add @opentelemetry/proto package
dyladan Dec 28, 2021
7e876b3
chore: autogenerate proto files on compile
dyladan Dec 28, 2021
d38c380
chore: add proto to tsconfig
dyladan Dec 28, 2021
27137ca
chore: add proto to submodle
dyladan Dec 28, 2021
00edec0
chore: add generate to lerna precompile
dyladan Dec 28, 2021
1a55158
chore: download submodules before compile
dyladan Dec 28, 2021
e8e4e2c
chore: move submodule to precompile
dyladan Dec 28, 2021
64312d3
chore: convert proto to protobufjs
dyladan Dec 29, 2021
27133e2
Merge remote-tracking branch 'origin/main' into generated-proto
dyladan Dec 29, 2021
2fd6f9c
chore(proto): export metrics function
dyladan Dec 29, 2021
76667f0
feat: add client classes for proto services
dyladan Jan 4, 2022
2042b28
Merge remote-tracking branch 'origin/main' into generated-proto
dyladan Jan 5, 2022
7efc596
Merge remote-tracking branch 'origin/main' into generated-proto
dyladan Jan 14, 2022
95c82e6
docs(proto): add readme to proto package
dyladan Jan 14, 2022
39b5868
chore: revert use of draft proto package in exporter
dyladan Jan 25, 2022
7c34f85
Merge remote-tracking branch 'origin/main' into generated-proto
dyladan Jan 25, 2022
fce9183
deps(proto): add mkdirp for platform-agnostic builds
dyladan Jan 25, 2022
ba0bb72
chore: lint
dyladan Jan 25, 2022
4bff0c1
Rename opentelemetry-proto to proto
dyladan Jan 25, 2022
d470e19
chore(proto): esm builds
dyladan Jan 25, 2022
1b02224
chore: fix proto submodule
dyladan Jan 25, 2022
7f4d14b
chore: fix compilation
dyladan Jan 25, 2022
0a6f13c
test(proto): test in browser
dyladan Jan 25, 2022
165e0c3
deps(proto): clean up dependencies
dyladan Jan 25, 2022
1e76d3a
Merge remote-tracking branch 'origin/main' into generated-proto
dyladan Jan 28, 2022
9598df7
chore: remove errant ms conversion
dyladan Jan 28, 2022
0305016
feat(proto): kvlistvalue conversion in anyValue
dyladan Jan 28, 2022
7bb1804
chore(proto): indent with 2 spaces
dyladan Jan 28, 2022
834bd62
docs(proto): add missing readme link
dyladan Jan 28, 2022
f254fc1
fix(proto): use hex for span and trace ids
dyladan Jan 28, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/peer-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ jobs:

- name: Check API dependency semantics (experimental)
working-directory: experimental
run: lerna exec --ignore propagation-validation-server --ignore @opentelemetry/selenium-tests --ignore @opentelemetry/api-metrics-wip "node ../../../scripts/peer-api-check.js"
run: lerna exec --ignore propagation-validation-server --ignore @opentelemetry/selenium-tests --ignore @opentelemetry/api-metrics-wip --ignore @opentelemetry/proto "node ../../../scripts/peer-api-check.js"
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
[submodule "experimental/packages/opentelemetry-exporter-metrics-otlp-proto/protos"]
path = experimental/packages/opentelemetry-exporter-metrics-otlp-proto/protos
url = https://github.com/open-telemetry/opentelemetry-proto.git
[submodule "experimental/packages/proto/opentelemetry-proto"]
path = experimental/packages/proto/opentelemetry-proto
url = https://github.com/open-telemetry/opentelemetry-proto
3 changes: 2 additions & 1 deletion .nycrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"test/**/*.*",
".eslintrc.js",
"karma.conf.js",
"webpack/*.js"
"webpack/*.js",
"src/generated/**"
],
"all": true
}
2 changes: 2 additions & 0 deletions experimental/packages/proto/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build
src/generated
8 changes: 8 additions & 0 deletions experimental/packages/proto/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
"env": {
"mocha": true,
"commonjs": true,
"shared-node-browser": true
},
...require('../../../eslint.config.js')
}
1 change: 1 addition & 0 deletions experimental/packages/proto/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/generated
113 changes: 113 additions & 0 deletions experimental/packages/proto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# OpenTelemetry Protocol

[![NPM Published Version][npm-img]][npm-url]
[![Apache License][license-image]][license-image]

This package provides everything needed to serialize [OpenTelemetry SDK][sdk] traces and metrics into the [OpenTelemetry Protocol][otlp] format using [protocol buffers][protobuf] or JSON.
dyladan marked this conversation as resolved.
Show resolved Hide resolved
It also contains service clients for exporting traces and metrics to the OpenTelemetry Collector or a compatible receiver using using OTLP over [gRPC][grpc].
This module uses [`protobufjs`][protobufjs] for serialization and is compatible with [`@grpc/grpc-js`][grpc-js].

## Quick Start

To get started you will need to install a compatible OpenTelemetry API.

### Install Peer Dependencies

```sh
npm install \
@opentelemetry/api \
@grpc/grpc-js # only required if you are using gRPC
```

### Serialize Traces and Metrics

This module exports functions to serialize traces and metrics from the OpenTelemetry SDK into protocol buffers which can be sent over HTTP to the OpenTelemetry collector or a compatible receiver.

```typescript
import { createExportTraceServiceRequest, createExportMetricsServiceRequest } from "@opentelemetry/proto";

const serializedSpans = createExportTraceServiceRequest(readableSpans);
const serializedMetrics = createExportMetricsServiceRequest(readableMetrics);
```

### Create gRPC Service Clients

This module also contains gRPC service clients for exporting traces and metrics to an OpenTelemetry collector or compatible receiver over gRPC.
In order to avoid bundling a gRPC module with this module, it is required to construct an RPC implementation to pass to the constructor of the service clients.
Any RPC implementation compatible with `grpc` or `@grpc/grpc-js` may be used, but `@grpc/grpc-js` is recommended.

```typescript
import type { RPCImpl } from 'protobufjs';
import { makeGenericClientConstructor, credentials } from '@gprc/grpc-js';
import { MetricServiceClient, TraceServiceClient } from "@opentelemetry/proto";

// Construct a RPC Implementation according to protobufjs docs
const GrpcClientConstructor = makeGenericClientConstructor({});

const metricGRPCClient = new GrpcClientConstructor(
"http://localhost:4317/v1/metrics", // default collector metrics endpoint
credentials.createInsecure(),
);

const traceGRPCClient = new GrpcClientConstructor(
"http://localhost:4317/v1/traces", // default collector traces endpoint
credentials.createInsecure(),
);

const metricRpc: RPCImpl = function(method, requestData, callback) {
metricGRPCClient.makeUnaryRequest(
method.name,
arg => arg,
arg => arg,
requestData,
callback
);
}

const traceRpc: RPCImpl = function(method, requestData, callback) {
traceGRPCClient.makeUnaryRequest(
method.name,
arg => arg,
arg => arg,
requestData,
callback
);
}

// Construct service clients to use RPC Implementations
const metricServiceClient = new MetricServiceClient({
rpcImpl: metricRpc,
startTime: Date.now() * 1000, // exporter start time in milliseconds
dyladan marked this conversation as resolved.
Show resolved Hide resolved
});

const traceServiceClient = new TraceServiceClient({
rpcImpl: traceRpc,
});

// Export ReadableSpan[] and ReadableMetric[] over gRPC
await metricServiceClient.export(readableMetrics);
await traceServiceClient.export(readableSpans);
```

## Useful links

- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
- For more about OpenTelemetry JavaScript: <https://github.com/open-telemetry/opentelemetry-js>
- 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/proto
[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fproto.svg

[sdk]: https://github.com/open-telemetry/opentelemetry-js
[protobuf]: https://developers.google.com/protocol-buffers
[grpc]: https://grpc.io/

[protobufjs]: https://www.npmjs.com/package/protobufjs
[grpc-js]: https://www.npmjs.com/package/@grpc/grpc-js
24 changes: 24 additions & 0 deletions experimental/packages/proto/karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*!
* 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
}))
};
1 change: 1 addition & 0 deletions experimental/packages/proto/opentelemetry-proto
Submodule opentelemetry-proto added at f8c59f
76 changes: 76 additions & 0 deletions experimental/packages/proto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"name": "@opentelemetry/proto",
"private": true,
"publishConfig": {
"access": "restricted"
},
"version": "0.27.0",
"description": "Transform OpenTelemetry SDK data into OTLP",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"repository": "open-telemetry/opentelemetry-js",
"scripts": {
"compile": "tsc --build tsconfig.all.json",
"generate": "npm run generate:js && npm run generate:types",
"generate:js": "mkdirp src/generated && pbjs -t static-module -w commonjs -o src/generated/index.js opentelemetry-proto/opentelemetry/**/*.proto",
"generate:types": "pbts -o src/generated/index.d.ts src/generated/index.js",
"clean": "tsc --build --clean tsconfig.all.json && rimraf src/generated",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"submodule": "git submodule sync --recursive && git submodule update --init --recursive",
"tdd": "npm run test -- --watch-extensions ts --watch",
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
"test:browser": "nyc karma start --single-run",
"watch": "npm run generate && tsc --build -w tsconfig.all.json",
"precompile": "npm run generate",
"prewatch": "npm run precompile"
},
"keywords": [
"opentelemetry",
"nodejs",
"grpc",
"protobuf",
"otlp",
"tracing",
"metrics"
],
"author": "OpenTelemetry Authors",
"license": "Apache-2.0",
"engines": {
"node": ">=8.0.0"
},
"files": [
"build/src/**/*.js",
"build/src/**/*.js.map",
"build/src/**/*.d.ts",
"LICENSE",
"README.md"
],
"devDependencies": {
"@opentelemetry/core": "1.0.1",
"@types/mocha": "8.2.3",
"istanbul-instrumenter-loader": "3.0.1",
"karma": "6.3.8",
"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",
"mkdirp": "1.0.4",
"mocha": "7.2.0",
"nyc": "15.1.0",
"rimraf": "3.0.2",
"ts-loader": "8.3.0",
"typescript": "4.4.4",
"webpack": "4.46.0"
},
"dependencies": {
"@opentelemetry/api": "^1.0.3",
"@opentelemetry/api-metrics": "0.27.0",
"@opentelemetry/resources": "1.0.1",
"@opentelemetry/sdk-metrics-base": "0.27.0",
"@opentelemetry/sdk-trace-base": "1.0.1",
"long": "^4.0.0",
"protobufjs": "6.11.2"
}
}
63 changes: 63 additions & 0 deletions experimental/packages/proto/src/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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, SpanAttributes } from '@opentelemetry/api';
import { opentelemetry } from './generated';
import Long = require('long');

const MAX_INTEGER_VALUE = 2147483647;
const MIN_INTEGER_VALUE = -2147483648;

export function toAttributes(
attributes: SpanAttributes
): opentelemetry.proto.common.v1.KeyValue[] {
return Object.keys(attributes).map(key => toKeyValue(key, attributes[key]));
}

export function toKeyValue(
key: string,
value: unknown
): opentelemetry.proto.common.v1.KeyValue {
return opentelemetry.proto.common.v1.KeyValue.fromObject({
dyladan marked this conversation as resolved.
Show resolved Hide resolved
key: key,
value: toAnyValue(value),
});
}

export function toAnyValue(value: unknown): opentelemetry.proto.common.v1.AnyValue {
return opentelemetry.proto.common.v1.AnyValue.fromObject({
Copy link
Contributor

Choose a reason for hiding this comment

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

What if value is an object? Shouldn't it be converted into kvlistValue?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

stringValue: typeof value === 'string' ? value : undefined,
doubleValue: typeof value === 'number' && !Number.isInteger(value) ? value : undefined,
intValue:
typeof value === 'number' &&
Number.isInteger(value) &&
value > MIN_INTEGER_VALUE &&
value < MAX_INTEGER_VALUE
? value
: undefined,
boolValue: typeof value === 'boolean' ? value : undefined,
bytesValue: value instanceof Uint8Array ? value : undefined,
arrayValue: Array.isArray(value) ? { values: value.map(v => toAnyValue(v)) } : undefined,
});
}

export function hexToBuf(hex: string): Uint8Array | undefined {
const ints = hex.match(/[\da-f]{2}/gi)?.map(h => parseInt(h, 16));
return ints && new Uint8Array(ints);
}

export function hrTimeToLong(hrtime: HrTime): Long {
return Long.fromInt(hrtime[0], true).mul(1e9).add(hrtime[1]);
}
25 changes: 25 additions & 0 deletions experimental/packages/proto/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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.
*/

// Required to use longjs to support unix timestamps in nanoseconds
import * as protobuf from 'protobufjs';
import Long = require('long');
dyladan marked this conversation as resolved.
Show resolved Hide resolved
protobuf.util.Long = Long;
protobuf.configure();

export * from './trace';
export * from './metrics';
export * from './types';
Loading