-
Notifications
You must be signed in to change notification settings - Fork 1k
fix(otlp-exporter-base): honor env proxy settings #6660
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -36,21 +36,54 @@ export interface OtlpNodeHttpConfiguration extends OtlpHttpConfiguration { | |||||||||||||||||||||||||||
| userAgent?: string; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| function hasEnvProxyEnvVar(name: string): boolean { | ||||||||||||||||||||||||||||
| return process.env[name] != null && process.env[name] !== ''; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| function hasEnvProxyConfiguration(): boolean { | ||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||
| process.env.NODE_USE_ENV_PROXY === '1' || | ||||||||||||||||||||||||||||
| hasEnvProxyEnvVar('HTTP_PROXY') || | ||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Node's > process.env.FOO = 42
42
> process.env.FOO
'42'so these hasEnvProxyEnvVar usages can be:
Suggested change
as Node.js core is doing: https://github.com/nodejs/node/blob/9fe7634c12a6ee7491729dc1e0a8c2020f87f8c4/lib/internal/process/pre_execution.js#L201-L204 |
||||||||||||||||||||||||||||
| hasEnvProxyEnvVar('http_proxy') || | ||||||||||||||||||||||||||||
| hasEnvProxyEnvVar('HTTPS_PROXY') || | ||||||||||||||||||||||||||||
| hasEnvProxyEnvVar('https_proxy') | ||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| function getEnvProxyAgentOptions(): | ||||||||||||||||||||||||||||
| | { proxyEnv: NodeJS.ProcessEnv } | ||||||||||||||||||||||||||||
| | undefined { | ||||||||||||||||||||||||||||
| if (hasEnvProxyConfiguration()) { | ||||||||||||||||||||||||||||
| // `proxyEnv` is used by Node.js' HTTP agents to honor HTTP(S)_PROXY | ||||||||||||||||||||||||||||
| // while preserving exporter-specific agent options such as keepAlive. | ||||||||||||||||||||||||||||
| return { proxyEnv: process.env }; | ||||||||||||||||||||||||||||
|
Comment on lines
+57
to
+59
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While we could pass in the full Perhaps:
Suggested change
I suppose a fair argument is that passing in |
||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return undefined; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export function httpAgentFactoryFromOptions( | ||||||||||||||||||||||||||||
| options: http.AgentOptions | https.AgentOptions | ||||||||||||||||||||||||||||
| ): HttpAgentFactory { | ||||||||||||||||||||||||||||
| return async protocol => { | ||||||||||||||||||||||||||||
| const isInsecure = protocol === 'http:'; | ||||||||||||||||||||||||||||
| const module = isInsecure ? import('http') : import('https'); | ||||||||||||||||||||||||||||
| const { Agent } = await module; | ||||||||||||||||||||||||||||
| const envProxyAgentOptions = getEnvProxyAgentOptions(); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (isInsecure) { | ||||||||||||||||||||||||||||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars -- these props should not be used in agent options | ||||||||||||||||||||||||||||
| const { ca, cert, key, ...insecureOptions } = | ||||||||||||||||||||||||||||
| options as https.AgentOptions; | ||||||||||||||||||||||||||||
| return new Agent(insecureOptions); | ||||||||||||||||||||||||||||
| return new Agent({ | ||||||||||||||||||||||||||||
| ...insecureOptions, | ||||||||||||||||||||||||||||
| ...envProxyAgentOptions, | ||||||||||||||||||||||||||||
| } as http.AgentOptions); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return new Agent(options); | ||||||||||||||||||||||||||||
| return new Agent({ | ||||||||||||||||||||||||||||
| ...options, | ||||||||||||||||||||||||||||
| ...envProxyAgentOptions, | ||||||||||||||||||||||||||||
|
Comment on lines
+80
to
+85
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should envProxyAgentOptions be applied before the passed in |
||||||||||||||||||||||||||||
| } as https.AgentOptions); | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,10 +3,93 @@ | |
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| import * as assert from 'assert'; | ||
| import { mergeOtlpNodeHttpConfigurationWithDefaults } from '../../../src/configuration/otlp-node-http-configuration'; | ||
| import * as http from 'http'; | ||
| import * as https from 'https'; | ||
| import { | ||
| httpAgentFactoryFromOptions, | ||
| mergeOtlpNodeHttpConfigurationWithDefaults, | ||
| } from '../../../src/configuration/otlp-node-http-configuration'; | ||
| import type { OtlpNodeHttpConfiguration } from '../../../src/configuration/otlp-node-http-configuration'; | ||
| import { VERSION } from '../../../src/version'; | ||
|
|
||
| const ENV_PROXY_VARIABLES = [ | ||
| 'NODE_USE_ENV_PROXY', | ||
| 'HTTP_PROXY', | ||
| 'http_proxy', | ||
| 'HTTPS_PROXY', | ||
| 'https_proxy', | ||
| ]; | ||
|
|
||
| function agentOptions(agent: http.Agent | https.Agent): any { | ||
| return (agent as any).options; | ||
| } | ||
|
|
||
| describe('httpAgentFactoryFromOptions', function () { | ||
| let originalEnv: Record<string, string | undefined>; | ||
|
|
||
| beforeEach(function () { | ||
| originalEnv = {}; | ||
| for (const envVar of ENV_PROXY_VARIABLES) { | ||
| originalEnv[envVar] = process.env[envVar]; | ||
| delete process.env[envVar]; | ||
| } | ||
| }); | ||
|
|
||
| afterEach(function () { | ||
| for (const envVar of ENV_PROXY_VARIABLES) { | ||
| if (originalEnv[envVar] == null) { | ||
| delete process.env[envVar]; | ||
| } else { | ||
| process.env[envVar] = originalEnv[envVar]; | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| it('creates protocol-specific agents with the provided options', async function () { | ||
| const factory = httpAgentFactoryFromOptions({ keepAlive: true }); | ||
|
|
||
| const httpAgent = (await factory('http:')) as http.Agent; | ||
| const httpsAgent = (await factory('https:')) as https.Agent; | ||
|
|
||
| assert.ok(httpAgent instanceof http.Agent); | ||
| assert.ok(httpsAgent instanceof https.Agent); | ||
| assert.strictEqual(agentOptions(httpAgent).keepAlive, true); | ||
| assert.strictEqual(agentOptions(httpsAgent).keepAlive, true); | ||
| assert.strictEqual(agentOptions(httpAgent).proxyEnv, undefined); | ||
| assert.strictEqual(agentOptions(httpsAgent).proxyEnv, undefined); | ||
| }); | ||
|
|
||
| it('passes proxyEnv to http agents when HTTP_PROXY is configured', async function () { | ||
| process.env.HTTP_PROXY = 'http://proxy.example:3128'; | ||
| const factory = httpAgentFactoryFromOptions({ keepAlive: true }); | ||
|
|
||
| const agent = (await factory('http:')) as http.Agent; | ||
|
|
||
| assert.strictEqual(agentOptions(agent).keepAlive, true); | ||
| assert.strictEqual(agentOptions(agent).proxyEnv, process.env); | ||
| }); | ||
|
|
||
| it('passes proxyEnv to https agents when HTTPS_PROXY is configured', async function () { | ||
| process.env.HTTPS_PROXY = 'http://proxy.example:3128'; | ||
| const factory = httpAgentFactoryFromOptions({ keepAlive: true }); | ||
|
|
||
| const agent = (await factory('https:')) as https.Agent; | ||
|
|
||
| assert.strictEqual(agentOptions(agent).keepAlive, true); | ||
| assert.strictEqual(agentOptions(agent).proxyEnv, process.env); | ||
| }); | ||
|
|
||
| it('passes proxyEnv to agents when NODE_USE_ENV_PROXY is enabled', async function () { | ||
| process.env.NODE_USE_ENV_PROXY = '1'; | ||
| const factory = httpAgentFactoryFromOptions({ keepAlive: true }); | ||
|
|
||
| const agent = (await factory('https:')) as https.Agent; | ||
|
|
||
| assert.strictEqual(agentOptions(agent).keepAlive, true); | ||
| assert.strictEqual(agentOptions(agent).proxyEnv, process.env); | ||
| }); | ||
|
Comment on lines
+82
to
+90
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drop this test, assuming agreement with dropping using NODE_USE_ENV_PROXY above. |
||
| }); | ||
|
|
||
| describe('mergeOtlpNodeHttpConfigurationWithDefaults', function () { | ||
| const testDefaults: OtlpNodeHttpConfiguration = { | ||
| url: 'http://default.example.test', | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This env var is for a user to tell
nodeto read proxy-related envvars, if there are any. This isn't an indication that there is proxy-related env.