Skip to content

Commit

Permalink
Merge branch 'main' into fix-general-endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
legendecas authored May 17, 2022
2 parents 8173b05 + a9c59da commit 294e544
Show file tree
Hide file tree
Showing 11 changed files with 277 additions and 43 deletions.
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ All notable changes to experimental packages in this project will be documented

* feat(exporters): update proto version and use otlp-transformer #2929 @pichlermarc
* fix(sdk-metrics-base): misbehaving aggregation temporality selector tolerance #2958 @legendecas
* feat(trace-otlp-grpc): configure security with env vars #2827 @svetlanabrennan
* feat(sdk-metrics-base): async instruments callback timeout #2742 @legendecas

### :bug: (Bug Fix)
Expand Down
31 changes: 20 additions & 11 deletions experimental/packages/exporter-trace-otlp-grpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');

const collectorOptions = {
// url is optional and can be omitted - default is localhost:4317
url: '<collector-hostname>:<port>',
// url is optional and can be omitted - default is http://localhost:4317
url: 'http://<collector-hostname>:<port>',
};

const provider = new BasicTracerProvider();
Expand All @@ -51,8 +51,8 @@ const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/sdk
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');

const collectorOptions = {
// url is optional and can be omitted - default is localhost:4317
url: '<collector-hostname>:<port>',
// url is optional and can be omitted - default is http://localhost:4317
url: 'http://<collector-hostname>:<port>',
credentials: grpc.credentials.createSsl(),
};

Expand Down Expand Up @@ -91,8 +91,8 @@ const metadata = new grpc.Metadata();
metadata.set('k', 'v');

const collectorOptions = {
// url is optional and can be omitted - default is localhost:4317
url: '<collector-hostname>:<port>',
// url is optional and can be omitted - default is http://localhost:4317
url: 'http://<collector-hostname>:<port>',
metadata, // // an optional grpc.Metadata object to be sent with each request
};

Expand Down Expand Up @@ -135,8 +135,8 @@ By default no compression will be used. To use compression, set it programmatica
const { CompressionAlgorithm } = require('@opentelemetry/exporter-trace-otlp-grpc');

const collectorOptions = {
// url is optional and can be omitted - default is localhost:4317
url: '<collector-hostname>:<port>',
// url is optional and can be omitted - default is http://localhost:4317
url: 'http://<collector-hostname>:<port>',
metadata, // // an optional grpc.Metadata object to be sent with each request
compression: CompressionAlgorithm.GZIP,
};
Expand All @@ -149,11 +149,20 @@ const exporter = new OTLPTraceExporter(collectorOptions);

| Environment variable | Description |
|----------------------|-------------|
| OTEL_EXPORTER_OTLP_TRACES_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_TRACES_COMPRESSION | The compression type to use on OTLP trace requests. Options include gzip. By default no compression will be used. |
| OTEL_EXPORTER_OTLP_COMPRESSION | The compression type to use on OTLP trace, metric, and log requests. Options include gzip. By default no compression will be used. |
> The per-signal environment variables (`OTEL_EXPORTER_OTLP_TRACES_TIMEOUT`) takes precedence and non-per-signal environment variable (`OTEL_EXPORTER_OTLP_TIMEOUT`).
| OTEL_EXPORTER_OTLP_TRACES_INSECURE | Whether to enable client transport security for the exporter's gRPC connection for trace requests. This option only applies to OTLP/gRPC when an endpoint is provided without the http or https scheme. Options include true or false. By default insecure is false which creates a secure connection. |
| OTEL_EXPORTER_OTLP_INSECURE | Whether to enable client transport security for the exporter's gRPC connection for trace, metric and log requests. This option only applies to OTLP/gRPC when an endpoint is provided without the http or https scheme. Options include true or false. By default insecure is false which creates a secure connection. |
| OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE | The path to the file containing trusted root certificate to use when verifying an OTLP trace server's TLS credentials. By default the host platform's trusted root certificate is used.|
| OTEL_EXPORTER_OTLP_CERTIFICATE | The path to the file containing trusted root certificate to use when verifying an OTLP trace, metric, or log server's TLS credentials. By default the host platform's trusted root certificate is used. |
| OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY | The path to the file containing private client key to use when verifying an OTLP trace client's TLS credentials. Must provide a client certificate/chain when providing a private client key. By default no client key file is used. |
| OTEL_EXPORTER_OTLP_CLIENT_KEY | The path to the file containing private client key to use when verifying an OTLP trace, metric or log client's TLS credentials. Must provide a client certificate/chain when providing a private client key. By default no client key file is used. |
| OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE | The path to the file containing trusted client certificate/chain for clients private key to use when verifying an OTLP trace server's TLS credentials. Must provide a private client key when providing a certificate/chain. By default no chain file is used. |
| OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE | The path to the file containing trusted client certificate/chain for clients private key to use when verifying an OTLP trace, metric and log server's TLS credentials. Must provide a private client key when providing a certificate/chain. By default no chain file is used. |
| OTEL_EXPORTER_OTLP_TRACES_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. |

> Settings configured programmatically take precedence over environment variables. Per-signal environment variables take precedence over non-per-signal environment variables.
## Running opentelemetry-collector locally to see the traces

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ import {
OTLPGRPCExporterConfigNode,
OTLPGRPCExporterNodeBase,
ServiceClientType,
validateAndNormalizeUrl
validateAndNormalizeUrl,
DEFAULT_COLLECTOR_URL
} from '@opentelemetry/otlp-grpc-exporter-base';
import { createExportTraceServiceRequest, IExportTraceServiceRequest } from '@opentelemetry/otlp-transformer';

const DEFAULT_COLLECTOR_URL = 'localhost:4317';

/**
* OTLP Trace Exporter for Node
*/
Expand Down Expand Up @@ -55,7 +54,7 @@ export class OTLPTraceExporter
? validateAndNormalizeUrl(getEnv().OTEL_EXPORTER_OTLP_TRACES_ENDPOINT)
: getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
? validateAndNormalizeUrl(getEnv().OTEL_EXPORTER_OTLP_ENDPOINT)
: DEFAULT_COLLECTOR_URL;
: validateAndNormalizeUrl(DEFAULT_COLLECTOR_URL);
}

getServiceClientType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ const testCollectorExporter = (params: TestParams) =>
fs.readFileSync('./test/certs/client.key'),
fs.readFileSync('./test/certs/client.crt')
)
: undefined;
: grpc.credentials.createInsecure();
collectorExporter = new OTLPTraceExporter({
url: 'grpcs://' + address,
url: 'https://' + address,
credentials,
metadata: params.metadata,
});
Expand Down Expand Up @@ -207,7 +207,7 @@ const testCollectorExporter = (params: TestParams) =>
fs.readFileSync('./test/certs/client.key'),
fs.readFileSync('./test/certs/client.crt')
)
: undefined;
: grpc.credentials.createInsecure();

const collectorExporterWithTimeout = new OTLPTraceExporter({
url: 'grpcs://' + address,
Expand Down Expand Up @@ -236,9 +236,9 @@ const testCollectorExporter = (params: TestParams) =>
fs.readFileSync('./test/certs/client.key'),
fs.readFileSync('./test/certs/client.crt')
)
: undefined;
: grpc.credentials.createInsecure();
collectorExporter = new OTLPTraceExporter({
url: 'grpcs://' + address,
url: 'https://' + address,
credentials,
metadata: params.metadata,
compression: CompressionAlgorithm.GZIP,
Expand Down Expand Up @@ -286,11 +286,11 @@ const testCollectorExporter = (params: TestParams) =>
fs.readFileSync('./test/certs/client.key'),
fs.readFileSync('./test/certs/client.crt')
)
: undefined;
: grpc.credentials.createInsecure();

envSource.OTEL_EXPORTER_OTLP_COMPRESSION = 'gzip';
collectorExporter = new OTLPTraceExporter({
url: 'grpcs://' + address,
url: 'https://' + address,
credentials,
metadata: params.metadata,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ The OTLPMetricsExporter in Node expects the URL to only be the hostname. It will
const { MeterProvider, PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics-base');
const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-grpc');
const collectorOptions = {
// url is optional and can be omitted - default is grpc://localhost:4317
url: 'grpc://<collector-hostname>:<port>',
// url is optional and can be omitted - default is http://localhost:4317
url: 'http://<collector-hostname>:<port>',
};

const exporter = new OTLPMetricExporter(collectorOptions);
Expand All @@ -48,6 +48,23 @@ const counter = meter.createCounter('metric_name');
counter.add(10, { 'key': 'value' });
```

## Environment Variable Configuration

| Environment variable | Description |
|----------------------|-------------|
| OTEL_EXPORTER_OTLP_METRICS_COMPRESSION | The compression type to use on OTLP metric requests. Options include gzip. By default no compression will be used. |
| OTEL_EXPORTER_OTLP_COMPRESSION | The compression type to use on OTLP trace, metric, and log requests. Options include gzip. By default no compression will be used. |
| OTEL_EXPORTER_OTLP_METRICS_INSECURE | Whether to enable client transport security for the exporter's gRPC connection for metric requests. This option only applies to OTLP/gRPC when an endpoint is provided without the http or https scheme. Options include true or false. By default insecure is false which creates a secure connection. |
| OTEL_EXPORTER_OTLP_INSECURE | Whether to enable client transport security for the exporter's gRPC connection for trace, metric and log requests. This option only applies to OTLP/gRPC when an endpoint is provided without the http or https scheme. Options include true or false. By default insecure is false which creates a secure connection. |
| OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE | The path to the file containing trusted root certificate to use when verifying an OTLP metric server's TLS credentials. By default the host platform's trusted root certificate is used.|
| OTEL_EXPORTER_OTLP_CERTIFICATE | The path to the file containing trusted root certificate to use when verifying an OTLP trace, metric, or log server's TLS credentials. By default the host platform's trusted root certificate is used. |
| OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY | The path to the file containing private client key to use when verifying an OTLP metric client's TLS credentials. Must provide a client certificate/chain when providing a private client key. By default no client key file is used. |
| OTEL_EXPORTER_OTLP_CLIENT_KEY | The path to the file containing private client key to use when verifying an OTLP trace, metric or log client's TLS credentials. Must provide a client certificate/chain when providing a private client key. By default no client key file is used. |
| OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE | The path to the file containing trusted client certificate/chain for clients private key to use when verifying an OTLP metric server's TLS credentials. Must provide a private client key when providing a certificate/chain. By default no chain file is used. |
| OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE | The path to the file containing trusted client certificate/chain for clients private key to use when verifying an OTLP trace, metric and log server's TLS credentials. Must provide a private client key when providing a certificate/chain. By default no chain file is used. |

> Settings configured programmatically take precedence over environment variables. Per-signal environment variables take precedence over non-per-signal environment variables.
## Running opentelemetry-collector locally to see the metrics

1. Go to `examples/otlp-exporter-node`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ import {
OTLPGRPCExporterConfigNode,
OTLPGRPCExporterNodeBase,
ServiceClientType,
validateAndNormalizeUrl
validateAndNormalizeUrl,
DEFAULT_COLLECTOR_URL
} from '@opentelemetry/otlp-grpc-exporter-base';
import { baggageUtils, getEnv } from '@opentelemetry/core';
import { Metadata } from '@grpc/grpc-js';
import { createExportMetricsServiceRequest, IExportMetricsServiceRequest } from '@opentelemetry/otlp-transformer';

const DEFAULT_COLLECTOR_URL = 'localhost:4317';


class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics, IExportMetricsServiceRequest> {

constructor(config: OTLPGRPCExporterConfigNode & OTLPMetricExporterOptions= defaultOptions) {
Expand All @@ -59,7 +57,7 @@ class OTLPMetricExporterProxy extends OTLPGRPCExporterNodeBase<ResourceMetrics,
? validateAndNormalizeUrl(getEnv().OTEL_EXPORTER_OTLP_METRICS_ENDPOINT)
: getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
? validateAndNormalizeUrl(getEnv().OTEL_EXPORTER_OTLP_ENDPOINT)
: DEFAULT_COLLECTOR_URL;
: validateAndNormalizeUrl(DEFAULT_COLLECTOR_URL);
}

convert(metrics: ResourceMetrics[]): IExportMetricsServiceRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ const testOTLPMetricExporter = (params: TestParams) =>
fs.readFileSync('./test/certs/client.key'),
fs.readFileSync('./test/certs/client.crt')
)
: undefined;
: grpc.credentials.createInsecure();
collectorExporter = new OTLPMetricExporter({
url: 'grpcs://' + address,
url: 'https://' + address,
credentials,
metadata: params.metadata,
temporalityPreference: AggregationTemporality.CUMULATIVE
Expand Down
2 changes: 1 addition & 1 deletion experimental/packages/otlp-grpc-exporter-base/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@

export * from './OTLPGRPCExporterNodeBase';
export { ServiceClientType, OTLPGRPCExporterConfigNode } from './types';
export { validateAndNormalizeUrl, GrpcCompressionAlgorithm } from './util';
export { DEFAULT_COLLECTOR_URL, validateAndNormalizeUrl, GrpcCompressionAlgorithm } from './util';
104 changes: 100 additions & 4 deletions experimental/packages/otlp-grpc-exporter-base/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@ import { getEnv, globalErrorHandler } from '@opentelemetry/core';
import * as path from 'path';
import { OTLPGRPCExporterNodeBase } from './OTLPGRPCExporterNodeBase';
import { URL } from 'url';
import * as fs from 'fs';
import { GRPCQueueItem, OTLPGRPCExporterConfigNode, ServiceClientType, } from './types';
import { CompressionAlgorithm, ExportServiceError, OTLPExporterError } from '@opentelemetry/otlp-exporter-base';

export const DEFAULT_COLLECTOR_URL = 'http://localhost:4317';

export function onInit<ExportItem, ServiceRequest>(
collector: OTLPGRPCExporterNodeBase<ExportItem, ServiceRequest>,
config: OTLPGRPCExporterConfigNode
): void {
collector.grpcQueue = [];
const credentials: grpc.ChannelCredentials =
config.credentials || grpc.credentials.createInsecure();

const credentials: grpc.ChannelCredentials = configureSecurity(config.credentials, collector.url);

const includeDirs = [path.resolve(__dirname, '..', 'protos')];

Expand Down Expand Up @@ -120,14 +123,107 @@ export function validateAndNormalizeUrl(url: string): string {
'URL path should not be set when using grpc, the path part of the URL will be ignored.'
);
}
if (target.protocol !== '' && !target.protocol?.match(/(http|grpc)s?/)) {
if (target.protocol !== '' && !target.protocol?.match(/^(http)s?:$/)) {
diag.warn(
'URL protocol should be http(s):// or grpc(s)://. Using grpc://.'
'URL protocol should be http(s)://. Using http://.'
);
}
return target.host;
}

export function configureSecurity(credentials: grpc.ChannelCredentials | undefined, endpoint: string):
grpc.ChannelCredentials {

let insecure: boolean;

if (credentials) {
return credentials;
} else if (endpoint.startsWith('https://')) {
insecure = false;
} else if (endpoint.startsWith('http://') || endpoint === DEFAULT_COLLECTOR_URL) {
insecure = true;
} else {
insecure = getSecurityFromEnv();
}

if (insecure) {
return grpc.credentials.createInsecure();
} else {
return useSecureConnection();
}
}

function getSecurityFromEnv(): boolean {
const definedInsecure =
getEnv().OTEL_EXPORTER_OTLP_TRACES_INSECURE ||
getEnv().OTEL_EXPORTER_OTLP_INSECURE;

if (definedInsecure) {
return definedInsecure.toLowerCase() === 'true';
} else {
return false;
}
}

export function useSecureConnection(): grpc.ChannelCredentials {
const rootCertPath = retrieveRootCert();
const privateKeyPath = retrievePrivateKey();
const certChainPath = retrieveCertChain();

return grpc.credentials.createSsl(rootCertPath, privateKeyPath, certChainPath);
}

function retrieveRootCert(): Buffer | undefined {
const rootCertificate =
getEnv().OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE ||
getEnv().OTEL_EXPORTER_OTLP_CERTIFICATE;

if (rootCertificate) {
try {
return fs.readFileSync(path.resolve(process.cwd(), rootCertificate));
} catch {
diag.warn('Failed to read root certificate file');
return undefined;
}
} else {
return undefined;
}
}

function retrievePrivateKey(): Buffer | undefined {
const clientKey =
getEnv().OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY ||
getEnv().OTEL_EXPORTER_OTLP_CLIENT_KEY;

if (clientKey) {
try {
return fs.readFileSync(path.resolve(process.cwd(), clientKey));
} catch {
diag.warn('Failed to read client certificate private key file');
return undefined;
}
} else {
return undefined;
}
}

function retrieveCertChain(): Buffer | undefined {
const clientChain =
getEnv().OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE ||
getEnv().OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE;

if (clientChain) {
try {
return fs.readFileSync(path.resolve(process.cwd(), clientChain));
} catch {
diag.warn('Failed to read client certificate chain file');
return undefined;
}
} else {
return undefined;
}
}

function toGrpcCompression(compression: CompressionAlgorithm): GrpcCompressionAlgorithm {
if(compression === CompressionAlgorithm.NONE)
return GrpcCompressionAlgorithm.NONE;
Expand Down
Loading

0 comments on commit 294e544

Please sign in to comment.