Skip to content

Commit 59b612a

Browse files
chore(otlp-exporter-base): use an http agent factory
1 parent 7d4481b commit 59b612a

14 files changed

+83
-69
lines changed

.mocharc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
require: `${__dirname}/ts-node.js`,
3+
};

.mocharc.yml

Lines changed: 0 additions & 1 deletion
This file was deleted.

experimental/packages/otlp-exporter-base/src/configuration/convert-legacy-node-http-options.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,22 @@
1616
import { OTLPExporterNodeConfigBase } from './legacy-node-configuration';
1717
import {
1818
getHttpConfigurationDefaults,
19+
HttpAgentFactory,
20+
httpAgentFactoryFromOptions,
1921
mergeOtlpHttpConfigurationWithDefaults,
2022
OtlpHttpConfiguration,
2123
} from './otlp-http-configuration';
2224
import { getHttpConfigurationFromEnvironment } from './otlp-http-env-configuration';
23-
import type * as http from 'http';
24-
import type * as https from 'https';
2525
import { diag } from '@opentelemetry/api';
2626
import { wrapStaticHeadersInFunction } from './shared-configuration';
2727

2828
function convertLegacyAgentOptions(
2929
config: OTLPExporterNodeConfigBase
30-
): http.AgentOptions | https.AgentOptions | undefined {
30+
): HttpAgentFactory | undefined {
31+
if (typeof config.httpAgentOptions === 'function') {
32+
return config.httpAgentOptions;
33+
}
34+
3135
// populate keepAlive for use with new settings
3236
if (config?.keepAlive != null) {
3337
if (config.httpAgentOptions != null) {
@@ -44,7 +48,11 @@ function convertLegacyAgentOptions(
4448
}
4549
}
4650

47-
return config.httpAgentOptions;
51+
if (config.httpAgentOptions != null) {
52+
return httpAgentFactoryFromOptions(config.httpAgentOptions);
53+
} else {
54+
return undefined;
55+
}
4856
}
4957

5058
/**
@@ -72,8 +80,7 @@ export function convertLegacyHttpOptions(
7280
concurrencyLimit: config.concurrencyLimit,
7381
timeoutMillis: config.timeoutMillis,
7482
compression: config.compression,
75-
agentOptions: convertLegacyAgentOptions(config),
76-
agent: config.httpAgent,
83+
agent: convertLegacyAgentOptions(config),
7784
},
7885
getHttpConfigurationFromEnvironment(signalIdentifier, signalResourcePath),
7986
getHttpConfigurationDefaults(requiredHeaders, signalResourcePath)

experimental/packages/otlp-exporter-base/src/configuration/legacy-node-configuration.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,16 @@
1818
import type * as http from 'http';
1919
import type * as https from 'https';
2020

21-
import { OTLPExporterConfigBase } from './legacy-base-configuration';
21+
import type { OTLPExporterConfigBase } from './legacy-base-configuration';
22+
import type { HttpAgentFactory } from './otlp-http-configuration';
2223

2324
/**
2425
* Collector Exporter node base config
2526
*/
2627
export interface OTLPExporterNodeConfigBase extends OTLPExporterConfigBase {
2728
keepAlive?: boolean;
2829
compression?: CompressionAlgorithm;
29-
httpAgentOptions?: http.AgentOptions | https.AgentOptions;
30-
/**
31-
* {@link httpAgentOptions} should be preferred in almost all cases.
32-
*
33-
* This option exists to allow passing an instance of a custom HTTP agent
34-
* class for advanced use cases.
35-
* Great care must be taken not to require the `http` module before it is
36-
* instrumented (for instance by importing the `Agent` class to extend it)
37-
* in CommonJS code, as this will break the instrumentation and no telemetry
38-
* data will be collected.
39-
*/
40-
httpAgent?: http.Agent | https.Agent;
30+
httpAgentOptions?: http.AgentOptions | https.AgentOptions | HttpAgentFactory;
4131
}
4232

4333
export enum CompressionAlgorithm {

experimental/packages/otlp-exporter-base/src/configuration/otlp-http-configuration.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ import { validateAndNormalizeHeaders } from '../util';
2525
import type * as http from 'http';
2626
import type * as https from 'https';
2727

28+
export type HttpAgentFactory =
29+
| ((protocol: string) => http.Agent)
30+
| ((protocol: string) => https.Agent)
31+
| ((protocol: string) => Promise<http.Agent>)
32+
| ((protocol: string) => Promise<https.Agent>);
33+
2834
export interface OtlpHttpConfiguration extends OtlpSharedConfiguration {
2935
url: string;
3036
headers: () => Record<string, string>;
31-
agentOptions: http.AgentOptions | https.AgentOptions;
32-
agent?: http.Agent | https.Agent;
37+
agent: HttpAgentFactory;
3338
}
3439

3540
function mergeHeaders(
@@ -72,6 +77,16 @@ function validateUserProvidedUrl(url: string | undefined): string | undefined {
7277
}
7378
}
7479

80+
export function httpAgentFactoryFromOptions(
81+
options: http.AgentOptions | https.AgentOptions
82+
): HttpAgentFactory {
83+
return async protocol => {
84+
const { Agent } =
85+
protocol === 'http:' ? await import('http') : await import('https');
86+
return new Agent(options);
87+
};
88+
}
89+
7590
/**
7691
* @param userProvidedConfiguration Configuration options provided by the user in code.
7792
* @param fallbackConfiguration Fallback to use when the {@link userProvidedConfiguration} does not specify an option.
@@ -97,10 +112,10 @@ export function mergeOtlpHttpConfigurationWithDefaults(
97112
validateUserProvidedUrl(userProvidedConfiguration.url) ??
98113
fallbackConfiguration.url ??
99114
defaultConfiguration.url,
100-
agentOptions:
101-
userProvidedConfiguration.agentOptions ??
102-
fallbackConfiguration.agentOptions ??
103-
defaultConfiguration.agentOptions,
115+
agent:
116+
userProvidedConfiguration.agent ??
117+
fallbackConfiguration.agent ??
118+
defaultConfiguration.agent,
104119
};
105120
}
106121

@@ -112,6 +127,6 @@ export function getHttpConfigurationDefaults(
112127
...getSharedConfigurationDefaults(),
113128
headers: () => requiredHeaders,
114129
url: 'http://localhost:4318/' + signalResourcePath,
115-
agentOptions: { keepAlive: true },
130+
agent: httpAgentFactoryFromOptions({ keepAlive: true }),
116131
};
117132
}

experimental/packages/otlp-exporter-base/src/index-node-http.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
export { httpAgentFactoryFromOptions } from './configuration/otlp-http-configuration';
1718
export { createOtlpHttpExportDelegate } from './otlp-http-export-delegate';
1819
export { getSharedConfigurationFromEnvironment } from './configuration/shared-env-configuration';
1920
export { convertLegacyHttpOptions } from './configuration/convert-legacy-node-http-options';

experimental/packages/otlp-exporter-base/src/transport/http-exporter-transport.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class HttpExporterTransport implements IExporterTransport {
3737
constructor(private _parameters: HttpRequestParameters) {}
3838

3939
async send(data: Uint8Array, timeoutMillis: number): Promise<ExportResponse> {
40-
const { agent, send } = this._loadUtils();
40+
const { agent, send } = await this._loadUtils();
4141

4242
return new Promise<ExportResponse>(resolve => {
4343
send(
@@ -56,22 +56,20 @@ class HttpExporterTransport implements IExporterTransport {
5656
// intentionally left empty, nothing to do.
5757
}
5858

59-
private _loadUtils(): Utils {
59+
private async _loadUtils(): Promise<Utils> {
6060
let utils = this._utils;
6161

6262
if (utils === null) {
63-
// Lazy require to ensure that http/https is not required before instrumentations can wrap it.
64-
const {
65-
sendWithHttp,
66-
createHttpAgent,
67-
// eslint-disable-next-line @typescript-eslint/no-var-requires
68-
} = require('./http-transport-utils');
63+
// Lazy import to ensure that http/https is not required before instrumentations can wrap it.
64+
const imported = await import('./http-transport-utils.js');
6965

7066
utils = this._utils = {
71-
agent:
72-
this._parameters.agent ??
73-
createHttpAgent(this._parameters.url, this._parameters.agentOptions),
74-
send: sendWithHttp,
67+
agent: await this._parameters.agent(
68+
new URL(this._parameters.url).protocol
69+
),
70+
// @ts-expect-error dynamic imports are never transpiled, but named exports only work when
71+
// dynamically importing an esm file, and the utils file might be transpiled to cjs
72+
send: imported.sendWithHttp ?? imported.default.sendWithHttp,
7573
};
7674
}
7775

experimental/packages/otlp-exporter-base/src/transport/http-transport-types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import type * as http from 'http';
1818
import type * as https from 'https';
1919
import { ExportResponse } from '../export-response';
20+
import { HttpAgentFactory } from '../configuration/otlp-http-configuration';
2021

2122
export type sendWithHttp = (
2223
params: HttpRequestParameters,
@@ -30,6 +31,5 @@ export interface HttpRequestParameters {
3031
url: string;
3132
headers: () => Record<string, string>;
3233
compression: 'gzip' | 'none';
33-
agentOptions: http.AgentOptions | https.AgentOptions;
34-
agent?: http.Agent | https.Agent;
34+
agent: HttpAgentFactory;
3535
}

experimental/packages/otlp-exporter-base/src/transport/http-transport-utils.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,3 @@ function readableFromUint8Array(buff: string | Uint8Array): Readable {
141141

142142
return readable;
143143
}
144-
145-
export function createHttpAgent(
146-
rawUrl: string,
147-
agentOptions: http.AgentOptions | https.AgentOptions
148-
) {
149-
const parsedUrl = new URL(rawUrl);
150-
const Agent = parsedUrl.protocol === 'http:' ? http.Agent : https.Agent;
151-
return new Agent(agentOptions);
152-
}

experimental/packages/otlp-exporter-base/test/common/configuration/otlp-http-configuration.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
OtlpHttpConfiguration,
2020
} from '../../../src/configuration/otlp-http-configuration';
2121
import * as assert from 'assert';
22+
import * as http from 'http';
2223
import { testSharedConfigBehavior } from './shared-configuration.test';
2324

2425
describe('mergeOtlpHttpConfigurationWithDefaults', function () {
@@ -28,7 +29,7 @@ describe('mergeOtlpHttpConfigurationWithDefaults', function () {
2829
compression: 'none',
2930
concurrencyLimit: 2,
3031
headers: () => ({ 'User-Agent': 'default-user-agent' }),
31-
agentOptions: { keepAlive: true },
32+
agent: () => new http.Agent({ keepAlive: true }),
3233
};
3334

3435
describe('headers', function () {

0 commit comments

Comments
 (0)