Skip to content

Commit 2f1e316

Browse files
pichlermarcdyladan
andauthored
feat(otlp-grpc-exporter-base): use statically generated protobuf code (#3705)
Co-authored-by: Daniel Dyla <[email protected]>
1 parent abfb1bb commit 2f1e316

File tree

14 files changed

+246
-72
lines changed

14 files changed

+246
-72
lines changed

experimental/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ All notable changes to experimental packages in this project will be documented
1111
* feat(otlp-transformer): support log records. [#3712](https://github.com/open-telemetry/opentelemetry-js/pull/3712/) @llc1123
1212
* feat(otlp-grpc-exporter-base): support log records. [#3712](https://github.com/open-telemetry/opentelemetry-js/pull/3712/) @llc1123
1313
* feat(exporter-logs-otlp-grpc): otlp-grpc exporter for logs. [#3712](https://github.com/open-telemetry/opentelemetry-js/pull/3712/) @llc1123
14+
* feat(otlp-grpc-exporter-base): use statically generated protobuf code [#3705](https://github.com/open-telemetry/opentelemetry-js/pull/3705) @pichlermarc
1415
* refactor(otlp-transformer): refine metric transformers. [#3770](https://github.com/open-telemetry/opentelemetry-js/pull/3770/) @llc1123
1516

1617
### :bug: (Bug Fix)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
src/generated/*
2+
!src/generated/.gitkeep

experimental/packages/otlp-grpc-exporter-base/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88
"scripts": {
99
"prepublishOnly": "npm run compile",
1010
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../../",
11-
"compile": "tsc --build",
11+
"compile": "npm run protos && tsc --build",
1212
"clean": "tsc --build --clean",
1313
"lint": "eslint . --ext .ts",
1414
"lint:fix": "eslint . --ext .ts --fix",
15-
"postcompile": "npm run submodule && npm run protos:copy",
16-
"protos:copy": "cpx protos/opentelemetry/**/*.* build/protos/opentelemetry",
15+
"protos": "npm run submodule && npm run protos:generate",
16+
"protos:generate": "node ../../../scripts/generate-protos.js",
1717
"submodule": "git submodule sync --recursive && git submodule update --init --recursive",
1818
"tdd": "npm run test -- --watch-extensions ts --watch",
1919
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
2020
"version": "node ../../../scripts/version-update.js",
21-
"watch": "npm run protos:copy && tsc -w",
21+
"watch": "npm run protos && tsc -w",
2222
"precompile": "lerna run version --scope $(npm pkg get name) --include-dependencies",
2323
"prewatch": "npm run precompile"
2424
},
@@ -40,7 +40,6 @@
4040
"build/src/**/*.js",
4141
"build/src/**/*.js.map",
4242
"build/src/**/*.d.ts",
43-
"build/protos/**/*.proto",
4443
"doc",
4544
"LICENSE",
4645
"README.md"
@@ -64,16 +63,17 @@
6463
"sinon": "15.0.0",
6564
"ts-loader": "8.4.0",
6665
"ts-mocha": "10.0.0",
67-
"typescript": "4.4.4"
66+
"typescript": "4.4.4",
67+
"protobufjs-cli": "1.0.2"
6868
},
6969
"peerDependencies": {
7070
"@opentelemetry/api": "^1.0.0"
7171
},
7272
"dependencies": {
7373
"@grpc/grpc-js": "^1.7.1",
74-
"@grpc/proto-loader": "^0.7.3",
7574
"@opentelemetry/core": "1.12.0",
76-
"@opentelemetry/otlp-exporter-base": "0.38.0"
75+
"@opentelemetry/otlp-exporter-base": "0.38.0",
76+
"protobufjs": "^7.2.2"
7777
},
7878
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/otlp-grpc-exporter-base",
7979
"sideEffects": false
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as root from './generated/root';
18+
import * as grpc from '@grpc/grpc-js';
19+
import { IExportLogsServiceRequest } from '@opentelemetry/otlp-transformer';
20+
import { ExportType } from './internal-types';
21+
import IExportLogsServiceResponse = root.opentelemetry.proto.collector.logs.v1.IExportLogsServiceResponse;
22+
23+
const responseType = root.opentelemetry.proto.collector.logs.v1
24+
.ExportLogsServiceResponse as ExportType<IExportLogsServiceResponse>;
25+
26+
const requestType = root.opentelemetry.proto.collector.logs.v1
27+
.ExportLogsServiceRequest as ExportType<IExportLogsServiceRequest>;
28+
29+
const logsServiceDefinition = {
30+
export: {
31+
path: '/opentelemetry.proto.collector.logs.v1.LogsService/Export',
32+
requestStream: false,
33+
responseStream: false,
34+
requestSerialize: (arg: IExportLogsServiceRequest) => {
35+
return Buffer.from(requestType.encode(arg).finish());
36+
},
37+
requestDeserialize: (arg: Buffer) => {
38+
return requestType.decode(arg);
39+
},
40+
responseSerialize: (arg: IExportLogsServiceResponse) => {
41+
return Buffer.from(responseType.encode(arg).finish());
42+
},
43+
responseDeserialize: (arg: Buffer) => {
44+
return responseType.decode(arg);
45+
},
46+
},
47+
};
48+
49+
// Creates a new instance of a gRPC service client for OTLP logs
50+
export const LogsExportServiceClient: grpc.ServiceClientConstructor =
51+
grpc.makeGenericClientConstructor(logsServiceDefinition, 'LogsExportService');
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as root from './generated/root';
18+
import * as grpc from '@grpc/grpc-js';
19+
import { IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer';
20+
import { ExportType } from './internal-types';
21+
import IExportMetricsServiceResponse = root.opentelemetry.proto.collector.metrics.v1.IExportMetricsServiceResponse;
22+
23+
const responseType = root.opentelemetry.proto.collector.metrics.v1
24+
.ExportMetricsServiceResponse as ExportType<IExportMetricsServiceResponse>;
25+
26+
const requestType = root.opentelemetry.proto.collector.metrics.v1
27+
.ExportMetricsServiceRequest as ExportType<IExportMetricsServiceRequest>;
28+
29+
const metricsServiceDefinition = {
30+
export: {
31+
path: '/opentelemetry.proto.collector.metrics.v1.MetricsService/Export',
32+
requestStream: false,
33+
responseStream: false,
34+
requestSerialize: (arg: IExportMetricsServiceRequest) => {
35+
return Buffer.from(requestType.encode(arg).finish());
36+
},
37+
requestDeserialize: (arg: Buffer) => {
38+
return requestType.decode(arg);
39+
},
40+
responseSerialize: (arg: IExportMetricsServiceResponse) => {
41+
return Buffer.from(responseType.encode(arg).finish());
42+
},
43+
responseDeserialize: (arg: Buffer) => {
44+
return responseType.decode(arg);
45+
},
46+
},
47+
};
48+
49+
// Creates a new instance of a gRPC service client for OTLP metrics
50+
export const MetricExportServiceClient: grpc.ServiceClientConstructor =
51+
grpc.makeGenericClientConstructor(
52+
metricsServiceDefinition,
53+
'MetricsExportService'
54+
);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as root from './generated/root';
18+
import * as grpc from '@grpc/grpc-js';
19+
import { IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer';
20+
import { ExportType } from './internal-types';
21+
import IExportTraceServiceResponse = root.opentelemetry.proto.collector.trace.v1.IExportTraceServiceResponse;
22+
23+
const responseType = root.opentelemetry.proto.collector.trace.v1
24+
.ExportTraceServiceResponse as ExportType<IExportTraceServiceResponse>;
25+
26+
const requestType = root.opentelemetry.proto.collector.trace.v1
27+
.ExportTraceServiceRequest as ExportType<IExportTraceServiceRequest>;
28+
29+
const traceServiceDefinition = {
30+
export: {
31+
path: '/opentelemetry.proto.collector.trace.v1.TraceService/Export',
32+
requestStream: false,
33+
responseStream: false,
34+
requestSerialize: (arg: IExportTraceServiceRequest) => {
35+
return Buffer.from(requestType.encode(arg).finish());
36+
},
37+
requestDeserialize: (arg: Buffer) => {
38+
return requestType.decode(arg);
39+
},
40+
responseSerialize: (arg: IExportTraceServiceResponse) => {
41+
return Buffer.from(responseType.encode(arg).finish());
42+
},
43+
responseDeserialize: (arg: Buffer) => {
44+
return responseType.decode(arg);
45+
},
46+
},
47+
};
48+
49+
// Creates a new instance of a gRPC service client for exporting OTLP traces
50+
export const TraceExportServiceClient: grpc.ServiceClientConstructor =
51+
grpc.makeGenericClientConstructor(
52+
traceServiceDefinition,
53+
'TraceExportService'
54+
);

experimental/packages/otlp-grpc-exporter-base/src/generated/.gitkeep

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type * as protobuf from 'protobufjs';
18+
19+
export interface ExportType<T, R = T & { toJSON: () => unknown }> {
20+
encode(message: T, writer?: protobuf.Writer): protobuf.Writer;
21+
decode(reader: protobuf.Reader | Uint8Array, length?: number): R;
22+
}

experimental/packages/otlp-grpc-exporter-base/src/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ export interface GRPCQueueItem<ExportedItem> {
3434
/**
3535
* Service Client for sending spans/metrics/logs
3636
*/
37-
export interface ServiceClient extends grpc.Client {
37+
export interface ServiceClient {
3838
export: (
3939
request: any,
4040
metadata: grpc.Metadata,
4141
options: grpc.CallOptions,
4242
callback: Function
4343
) => {};
44+
45+
close(): void;
4446
}
4547

4648
/**

experimental/packages/otlp-grpc-exporter-base/src/util.ts

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
import * as grpc from '@grpc/grpc-js';
18-
import * as protoLoader from '@grpc/proto-loader';
1918
import { diag } from '@opentelemetry/api';
2019
import { getEnv, globalErrorHandler } from '@opentelemetry/core';
2120
import * as path from 'path';
@@ -28,11 +27,15 @@ import {
2827
ServiceClientType,
2928
} from './types';
3029
import {
31-
CompressionAlgorithm,
3230
ExportServiceError,
3331
OTLPExporterError,
32+
CompressionAlgorithm,
3433
} from '@opentelemetry/otlp-exporter-base';
3534

35+
import { MetricExportServiceClient } from './MetricsExportServiceClient';
36+
import { TraceExportServiceClient } from './TraceExportServiceClient';
37+
import { LogsExportServiceClient } from './LogsExportServiceClient';
38+
3639
export const DEFAULT_COLLECTOR_URL = 'http://localhost:4317';
3740

3841
export function onInit<ExportItem, ServiceRequest>(
@@ -46,61 +49,41 @@ export function onInit<ExportItem, ServiceRequest>(
4649
collector.getUrlFromConfig(config)
4750
);
4851

49-
const includeDirs = [path.resolve(__dirname, '..', 'protos')];
52+
try {
53+
if (collector.getServiceClientType() === ServiceClientType.SPANS) {
54+
const client = new TraceExportServiceClient(collector.url, credentials, {
55+
'grpc.default_compression_algorithm': collector.compression.valueOf(),
56+
});
5057

51-
protoLoader
52-
.load(collector.getServiceProtoPath(), {
53-
keepCase: false,
54-
longs: String,
55-
enums: String,
56-
defaults: true,
57-
oneofs: true,
58-
includeDirs,
59-
})
60-
.then(packageDefinition => {
61-
const packageObject: any = grpc.loadPackageDefinition(packageDefinition);
58+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
59+
// @ts-ignore
60+
collector.serviceClient = client;
61+
} else if (collector.getServiceClientType() === ServiceClientType.METRICS) {
62+
const client = new MetricExportServiceClient(collector.url, credentials, {
63+
'grpc.default_compression_algorithm': collector.compression.valueOf(),
64+
});
6265

63-
const options = {
64-
'grpc.default_compression_algorithm': collector.compression,
65-
};
66-
67-
switch (collector.getServiceClientType()) {
68-
case ServiceClientType.SPANS:
69-
collector.serviceClient =
70-
new packageObject.opentelemetry.proto.collector.trace.v1.TraceService(
71-
collector.url,
72-
credentials,
73-
options
74-
);
75-
break;
76-
case ServiceClientType.METRICS:
77-
collector.serviceClient =
78-
new packageObject.opentelemetry.proto.collector.metrics.v1.MetricsService(
79-
collector.url,
80-
credentials,
81-
options
82-
);
83-
break;
84-
case ServiceClientType.LOGS:
85-
collector.serviceClient =
86-
new packageObject.opentelemetry.proto.collector.logs.v1.LogsService(
87-
collector.url,
88-
credentials,
89-
options
90-
);
91-
break;
92-
}
66+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
67+
// @ts-ignore
68+
collector.serviceClient = client;
69+
} else if (collector.getServiceClientType() === ServiceClientType.LOGS) {
70+
const client = new LogsExportServiceClient(collector.url, credentials, {
71+
'grpc.default_compression_algorithm': collector.compression.valueOf(),
72+
});
9373

94-
if (collector.grpcQueue.length > 0) {
95-
const queue = collector.grpcQueue.splice(0);
96-
queue.forEach((item: GRPCQueueItem<ExportItem>) => {
97-
collector.send(item.objects, item.onSuccess, item.onError);
98-
});
99-
}
100-
})
101-
.catch(err => {
102-
globalErrorHandler(err);
74+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
75+
// @ts-ignore
76+
collector.serviceClient = client;
77+
}
78+
} catch (err) {
79+
globalErrorHandler(err);
80+
}
81+
if (collector.grpcQueue.length > 0) {
82+
const queue = collector.grpcQueue.splice(0);
83+
queue.forEach((item: GRPCQueueItem<ExportItem>) => {
84+
collector.send(item.objects, item.onSuccess, item.onError);
10385
});
86+
}
10487
}
10588

10689
export function send<ExportItem, ServiceRequest>(

0 commit comments

Comments
 (0)