Skip to content

Commit

Permalink
feat(exporters)!: rewrite exporter config logic
Browse files Browse the repository at this point in the history
  • Loading branch information
pichlermarc committed Sep 2, 2024
1 parent 1fc304c commit 5de03f0
Show file tree
Hide file tree
Showing 50 changed files with 998 additions and 2,230 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,14 @@
*/

import { LogRecordExporter, ReadableLogRecord } from '@opentelemetry/sdk-logs';
import { baggageUtils, getEnv } from '@opentelemetry/core';
import {
OTLPGRPCExporterConfigNode,
OTLPGRPCExporterNodeBase,
validateAndNormalizeUrl,
DEFAULT_COLLECTOR_URL,
} from '@opentelemetry/otlp-grpc-exporter-base';
import {
IExportLogsServiceResponse,
ProtobufLogsSerializer,
} from '@opentelemetry/otlp-transformer';
import { VERSION } from './version';

const USER_AGENT = {
'User-Agent': `OTel-OTLP-Exporter-JavaScript/${VERSION}`,
};

/**
* OTLP Logs Exporter for Node
Expand All @@ -43,34 +35,12 @@ export class OTLPLogExporter
implements LogRecordExporter
{
constructor(config: OTLPGRPCExporterConfigNode = {}) {
const signalSpecificMetadata = {
...USER_AGENT,
...baggageUtils.parseKeyPairsIntoRecord(
getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
),
};
super(
config,
signalSpecificMetadata,
ProtobufLogsSerializer,
'LogsExportService',
'/opentelemetry.proto.collector.logs.v1.LogsService/Export',
ProtobufLogsSerializer
);
}

getDefaultUrl(config: OTLPGRPCExporterConfigNode) {
return validateAndNormalizeUrl(this.getUrlFromConfig(config));
}

getUrlFromConfig(config: OTLPGRPCExporterConfigNode): string {
if (typeof config.url === 'string') {
return config.url;
}

return (
getEnv().OTEL_EXPORTER_OTLP_LOGS_ENDPOINT ||
getEnv().OTEL_EXPORTER_OTLP_ENDPOINT ||
DEFAULT_COLLECTOR_URL
'LOGS'
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import {
IExportLogsServiceRequest,
IResourceLogs,
} from '@opentelemetry/otlp-transformer';
import { VERSION } from '../src/version';

const logsServiceProtoPath =
'opentelemetry/proto/collector/logs/v1/logs_service.proto';
Expand Down Expand Up @@ -294,104 +293,9 @@ const testCollectorExporter = (params: TestParams) => {
}, 500);
});
});
describe('Logs Exporter with compression', () => {
const envSource = process.env;
it('should return gzip compression algorithm on exporter', () => {
const credentials = useTLS
? grpc.credentials.createSsl(
fs.readFileSync('./test/certs/ca.crt'),
fs.readFileSync('./test/certs/client.key'),
fs.readFileSync('./test/certs/client.crt')
)
: grpc.credentials.createInsecure();

envSource.OTEL_EXPORTER_OTLP_COMPRESSION = 'gzip';
collectorExporter = new OTLPLogExporter({
url: address,
credentials,
metadata: metadata,
});
assert.strictEqual(
collectorExporter.compression,
CompressionAlgorithm.GZIP
);
delete envSource.OTEL_EXPORTER_OTLP_COMPRESSION;
});
});
});
};

describe('OTLPLogExporter - node (getDefaultUrl)', () => {
it('should default to localhost', done => {
const collectorExporter = new OTLPLogExporter({});
setTimeout(() => {
assert.strictEqual(collectorExporter['url'], 'localhost:4317');
done();
});
});
it('should keep the URL if included', done => {
const url = 'http://foo.bar.com';
const collectorExporter = new OTLPLogExporter({ url });
setTimeout(() => {
assert.strictEqual(collectorExporter['url'], 'foo.bar.com');
done();
});
});
});

describe('when configuring via environment', () => {
const envSource = process.env;

afterEach(function () {
// Ensure we don't pollute other tests if assertions fail
delete envSource.OTEL_EXPORTER_OTLP_ENDPOINT;
delete envSource.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
delete envSource.OTEL_EXPORTER_OTLP_HEADERS;
delete envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS;
sinon.restore();
});

it('should use url defined in env', () => {
envSource.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://foo.bar';
const collectorExporter = new OTLPLogExporter();
assert.strictEqual(collectorExporter.url, 'foo.bar');
});
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 OTLPLogExporter();
assert.strictEqual(collectorExporter.url, 'foo.logs');
});
it('should include user-agent header by default', () => {
const collectorExporter = new OTLPLogExporter();
const actualMetadata =
collectorExporter['_transport']['_parameters'].metadata();
assert.deepStrictEqual(actualMetadata.get('User-Agent'), [
`OTel-OTLP-Exporter-JavaScript/${VERSION}`,
]);
});
it('should use headers defined via env', () => {
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar';
const collectorExporter = new OTLPLogExporter();
const actualMetadata =
collectorExporter['_transport']['_parameters'].metadata();
assert.deepStrictEqual(actualMetadata.get('foo'), ['bar']);
});
it('should not override hard-coded headers config with headers defined via env', () => {
const metadata = new grpc.Metadata();
metadata.set('foo', 'bar');
metadata.set('goo', 'lol');
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=jar,bar=foo';
envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=boo';
const collectorExporter = new OTLPLogExporter({ metadata });
const actualMetadata =
collectorExporter['_transport']['_parameters'].metadata();
assert.deepStrictEqual(actualMetadata.get('foo'), ['bar']);
assert.deepStrictEqual(actualMetadata.get('goo'), ['lol']);
assert.deepStrictEqual(actualMetadata.get('bar'), ['foo']);
});
});

testCollectorExporter({ useTLS: true });
testCollectorExporter({ useTLS: false });
testCollectorExporter({ metadata });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export class OTLPLogExporter
...config,
},
JsonLogsSerializer,
'application/json'
{
'Content-Type': 'application/json',
},
'v1/logs'
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@ import type {
} from '@opentelemetry/sdk-logs';
import type { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
import type { IExportLogsServiceResponse } from '@opentelemetry/otlp-transformer';
import { getEnv, baggageUtils } from '@opentelemetry/core';
import {
OTLPExporterNodeBase,
parseHeaders,
} from '@opentelemetry/otlp-exporter-base';
import { JsonLogsSerializer } from '@opentelemetry/otlp-transformer';

import { getDefaultUrl } from '../config';
import { VERSION } from '../../version';

const USER_AGENT = {
Expand All @@ -42,25 +39,17 @@ export class OTLPLogExporter
implements LogRecordExporter
{
constructor(config: OTLPExporterNodeConfigBase = {}) {
// load OTEL_EXPORTER_OTLP_LOGS_TIMEOUT env
super(
{
timeoutMillis: getEnv().OTEL_EXPORTER_OTLP_LOGS_TIMEOUT,
...config,
},
JsonLogsSerializer,
{
...baggageUtils.parseKeyPairsIntoRecord(
getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
),
...parseHeaders(config?.headers),
...USER_AGENT,
'Content-Type': 'application/json',
}
},
'LOGS',
'v1/logs'
);
}

getDefaultUrl(config: OTLPExporterNodeConfigBase): string {
return getDefaultUrl(config);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import * as assert from 'assert';
import * as sinon from 'sinon';

import * as Config from '../../src/platform/config';
import { OTLPLogExporter } from '../../src/platform/browser';
import { OTLPExporterConfigBase } from '@opentelemetry/otlp-exporter-base';
import { ReadableLogRecord } from '@opentelemetry/sdk-logs';
Expand All @@ -38,16 +37,6 @@ describe('OTLPLogExporter', () => {
});
});

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);
});
});

describe('export - common', () => {
let spySend: any;
beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { diag } from '@opentelemetry/api';
import * as assert from 'assert';
import * as http from 'http';
import * as sinon from 'sinon';
import * as Config from '../../src/platform/config';

import { OTLPLogExporter } from '../../src/platform/node';
import { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
Expand Down Expand Up @@ -103,15 +102,6 @@ describe('OTLPLogExporter', () => {
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;
});

it('should override headers defined via env with headers defined in constructor', () => {
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo';
const exporter = new OTLPLogExporter({
Expand All @@ -131,23 +121,12 @@ describe('OTLPLogExporter', () => {
});
});

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);
});
});

describe('export', () => {
beforeEach(() => {
collectorExporterConfig = {
headers: {
foo: 'bar',
},
hostname: 'foo',
url: 'http://foo.bar.com',
keepAlive: true,
httpAgentOptions: { keepAliveMsecs: 2000 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ import {

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
*/
Expand All @@ -36,14 +33,11 @@ export class OTLPLogExporter
implements LogRecordExporter
{
constructor(config: OTLPExporterConfigBase = {}) {
super(config, ProtobufLogsSerializer, 'application/x-protobuf');
}

getDefaultUrl(config: OTLPExporterConfigBase): string {
if (typeof config.url === 'string') {
return config.url;
}

return DEFAULT_COLLECTOR_URL;
super(
config,
ProtobufLogsSerializer,
{ 'Content-Type': 'application/x-protobuf' },
'v1/logs'
);
}
}
Loading

0 comments on commit 5de03f0

Please sign in to comment.