Skip to content

Commit c654eaa

Browse files
committed
[#371] Add ConfigurationBuilder for flexible config management
1 parent b4497ec commit c654eaa

File tree

15 files changed

+337
-255
lines changed

15 files changed

+337
-255
lines changed

index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
const { AgentBuilder } = require('./lib/agent-builder')
1010
const AgentInfo = require('./lib/data/dto/agent-info')
11-
const { getConfig } = require('./lib/config')
11+
const { ConfigBuilder, setConfig } = require('./lib/config')
1212
const { LogBuilder } = require('./lib/utils/log/log-builder')
1313
const logger = require('./lib/utils/log/logger')
1414

15-
const config = getConfig()
15+
const config = new ConfigBuilder().build()
16+
setConfig(config)
1617
logger.setRootLogger(LogBuilder.createDefaultLogBuilder().setConfig(config).build())
1718

1819
const agentInfo = AgentInfo.make(config)

lib/agent-builder.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Apache License v2.0
55
*/
66

7-
import { PinpointConfig } from './config';
7+
import { Config } from './config';
88
import AgentInfo = require('./data/dto/agent-info');
99

1010
interface TraceObject {
@@ -25,7 +25,7 @@ interface DataSender {
2525

2626
interface Agent {
2727
agentInfo: AgentInfo;
28-
config: PinpointConfig;
28+
config: Config;
2929
dataSender: DataSender;
3030
traceContext: TraceContext;
3131
services: Array<() => void>;
@@ -42,7 +42,7 @@ interface Agent {
4242
declare class AgentBuilder {
4343
constructor(agentInfo: AgentInfo);
4444

45-
setConfig(config: PinpointConfig): AgentBuilder;
45+
setConfig(config: Config): AgentBuilder;
4646
setDataSender(dataSender: DataSender): AgentBuilder;
4747
addService(service: () => void): AgentBuilder;
4848
disableStatsScheduler(): AgentBuilder;

lib/config.d.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export interface LoggerLevels {
88
[loggerName: string]: string;
99
}
1010

11-
export interface PinpointConfig {
11+
export interface Config {
1212
enable: boolean;
1313
agentId: string;
1414
agentName?: string;
@@ -40,11 +40,14 @@ export interface PinpointConfig {
4040
[key: string]: any;
4141
}
4242

43-
export declare function getConfig(initOptions?: { [key: string]: any }): PinpointConfig;
43+
export declare class ConfigBuilder {
44+
constructor(agentStartupUserDefinedJson?: { [key: string]: any });
45+
setDefaultJson(json: { [key: string]: any }): ConfigBuilder;
46+
setUserDefinedJson(json: { [key: string]: any }): ConfigBuilder;
47+
build(): Config;
48+
}
49+
50+
export declare function getConfig(initOptions?: { [key: string]: any }): Config;
51+
export declare function setConfig(config: Config): void;
4452
export declare function clear(): void;
45-
export declare function readConfigJson(formattedConfig: any): Partial<PinpointConfig>;
46-
export declare function readRootConfigFile(): { [key: string]: any };
47-
export declare function getMainModulePath(requireFunction: NodeRequire): string | undefined;
4853
export declare function isContainerEnvironment(): boolean;
49-
export declare function initializeConfig(initOptions?: { [key: string]: any }): void;
50-
export declare function registerLoadedConfig(propertyName: string, callback: (value: any) => void): void;

lib/config.js

Lines changed: 142 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88

99
const path = require('path')
1010
const fs = require('fs')
11-
const defaultConfig = require('./pinpoint-config-default')
1211
const log = require('./utils/log/logger')
1312
const ServiceConfigBuilder = require('./client/retry/service-config-builder')
1413
const { randomBytes } = require('node:crypto')
1514
const levels = require('loglevel').levels
15+
const defaultConfig = require('./pinpoint-config-default')
16+
1617

1718
const valueOfString = (envName) => {
1819
return () => {
@@ -136,96 +137,6 @@ const ARRAY_CONFIG = [
136137
'traceExclusionUrlPatterns'
137138
]
138139

139-
const configurationValueValidations = {
140-
validateTraceExclusionUrlCacheSize: () => {
141-
if (typeof agentConfig.traceExclusionUrlCacheSize !== 'undefined' && typeof agentConfig.traceExclusionUrlPatterns === 'undefined') {
142-
delete agentConfig.traceExclusionUrlCacheSize
143-
log.warn(`You have to set the PINPOINT_TRACE_EXCLUSION_URL_PATTERN, PINPOINT_TRACE_EXCLUSION_URL_CACHE_SIZE or trace-exclusion-url{ pattern: 'pattern', 'cache-size': 100} for using excludsion url cache.`)
144-
}
145-
146-
if (Array.isArray(agentConfig.traceExclusionUrlPatterns) && Number.isInteger(agentConfig.traceExclusionUrlCacheSize)) {
147-
if (agentConfig.traceExclusionUrlCacheSize < 100) {
148-
agentConfig.traceExclusionUrlCacheSize = 100
149-
}
150-
}
151-
},
152-
validateIds: () => {
153-
[{ id: agentConfig.agentId, name: 'Agent ID', maxLength: 24, required: true }
154-
, { id: agentConfig.applicationName, name: 'Application Name', maxLength: 24, required: true }
155-
// Java PinpointConstants.AGENT_NAME_MAX_LEN = 255
156-
, { id: agentConfig.agentName, name: 'Agent Name', maxLength: 255, required: false }
157-
].filter(id => id.id)
158-
.filter(id => {
159-
if (isNaN(id.maxLength)) {
160-
return false
161-
}
162-
163-
if (id.required && typeof id.id !== 'string') {
164-
agentConfig.enable = false
165-
log.warn(`You have to set ${id.name}`)
166-
return false
167-
}
168-
169-
if (id.required === false && typeof id.id !== 'string') {
170-
return false
171-
}
172-
173-
const maxLength = id.maxLength
174-
const idRegex = /^[a-zA-Z0-9\\._\\-]+$/
175-
176-
if (id.id.length < 1) {
177-
agentConfig.enable = false
178-
log.warn(`You have to set ${id.name}`)
179-
return false
180-
}
181-
182-
if (id.id.length > maxLength) {
183-
agentConfig.enable = false
184-
log.warn(`You have to set ${id.name} to less ${maxLength} characters.`)
185-
return false
186-
}
187-
188-
if (!idRegex.test(id.id)) {
189-
agentConfig.enable = false
190-
log.warn(`invalidate ${id.name} name with /[a-zA-Z0-9\\._\\-]+/ RegExp`)
191-
return false
192-
}
193-
})
194-
}
195-
}
196-
197-
const init = (initOptions = {}) => {
198-
agentConfig = Object.assign({},
199-
readConfigJson(defaultConfig),
200-
readConfigJson(readRootConfigFile()),
201-
readFromEnv(),
202-
readConfigJson(initOptions))
203-
204-
Object.entries(REQUIRE_CONFIG).forEach(([propertyName, description]) => {
205-
if (propertyName === 'agentId' && !agentConfig[propertyName]) {
206-
return agentConfig.agentId = randomBytes(8).toString('hex')
207-
}
208-
if (agentConfig.enable && !agentConfig[propertyName]) {
209-
agentConfig.enable = false
210-
log.warn(`You must set ${description}.The Pinpoint Node JS Agent has been shutdown.`)
211-
}
212-
})
213-
214-
if (!ENV_MAP.container() && isContainerEnvironment()) {
215-
agentConfig.container = true
216-
}
217-
218-
for (const [key, validation] of Object.entries(configurationValueValidations)) {
219-
validation()
220-
}
221-
222-
if (typeof initOptions['grpc.service_config'] === 'object') {
223-
agentConfig.grpcServiceConfig = new ServiceConfigBuilder().setJSON(initOptions['grpc.service_config']).build()
224-
} else {
225-
agentConfig.grpcServiceConfig = ServiceConfigBuilder.nullObject.build()
226-
}
227-
}
228-
229140
const readFromEnv = () => {
230141
return Object.entries(ENV_MAP).reduce((acc, [key, valueOf]) => {
231142
const value = valueOf()
@@ -283,27 +194,6 @@ const getValue = (key, configFile) => {
283194
}
284195
}
285196

286-
const getConfig = (initOptions) => {
287-
if (!agentConfig) {
288-
init(initOptions)
289-
}
290-
return agentConfig
291-
}
292-
293-
const initializeConfig = (initOptions) => {
294-
clear()
295-
init(initOptions)
296-
loadedConfigCallbacks.forEach(callback => {
297-
try {
298-
callback.callback(agentConfig[callback.propertyName])
299-
} catch (e) {
300-
log.error('Error in loadedConfig callback', e)
301-
}
302-
})
303-
}
304-
305-
const clear = () => agentConfig && (agentConfig = null)
306-
307197
//https://github.com/sindresorhus/is-docker
308198
const isContainerEnvironment = () => {
309199
return hasDockerEnv() || hasDockerCGroup() || (process.env['KUBERNETES_SERVICE_HOST'] && process.env['KUBERNETES_SERVICE_HOST'].length > 0)
@@ -326,24 +216,153 @@ function hasDockerCGroup() {
326216
}
327217
}
328218

329-
let agentConfig
219+
class Config {
220+
constructor(config) {
221+
Object.assign(this, config)
222+
Object.freeze(this)
223+
}
224+
}
225+
226+
class ConfigBuilder {
227+
constructor(agentStartupUserDefinedJson = {}) {
228+
this.agentStartupUserDefinedJson = agentStartupUserDefinedJson
229+
}
330230

331-
const loadedConfigCallbacks = []
332-
function registerLoadedConfig(propertyName, callback) {
333-
if (typeof propertyName !== 'string' || typeof callback !== 'function') {
334-
return
231+
setDefaultJson(json) {
232+
this.defaultJson = json
233+
return this
335234
}
336235

337-
loadedConfigCallbacks.push({ propertyName, callback })
236+
setUserDefinedJson(json) {
237+
this.userDefinedJson = json
238+
return this
239+
}
240+
241+
build() {
242+
if (!this.defaultJson) {
243+
this.defaultJson = defaultConfig
244+
}
245+
246+
if (!this.userDefinedJson) {
247+
this.userDefinedJson = readRootConfigFile()
248+
}
249+
250+
const config = Object.assign({},
251+
readConfigJson(this.defaultJson),
252+
readConfigJson(this.userDefinedJson),
253+
readFromEnv(),
254+
readConfigJson(this.agentStartupUserDefinedJson))
255+
256+
Object.entries(REQUIRE_CONFIG).forEach(([propertyName, description]) => {
257+
if (propertyName === 'agentId' && !config[propertyName]) {
258+
return config.agentId = randomBytes(8).toString('hex')
259+
}
260+
if (config.enable && !config[propertyName]) {
261+
config.enable = false
262+
log.warn(`You must set ${description}.The Pinpoint Node JS Agent has been shutdown.`)
263+
}
264+
})
265+
266+
if (!ENV_MAP.container() && isContainerEnvironment()) {
267+
config.container = true
268+
}
269+
270+
for (const [key, validation] of Object.entries(valueValidations)) {
271+
validation(config)
272+
}
273+
274+
if (typeof this.agentStartupUserDefinedJson?.grpc?.service_config === 'object') {
275+
config.grpcServiceConfig = new ServiceConfigBuilder().setJSON(this.agentStartupUserDefinedJson.grpc.service_config).build()
276+
} else {
277+
config.grpcServiceConfig = ServiceConfigBuilder.nullObject.build()
278+
}
279+
return new Config(config)
280+
}
338281
}
339282

283+
const valueValidations = {
284+
validateTraceExclusionUrlCacheSize: (config) => {
285+
if (typeof config.traceExclusionUrlCacheSize !== 'undefined' && typeof config.traceExclusionUrlPatterns === 'undefined') {
286+
delete config.traceExclusionUrlCacheSize
287+
log.warn(`You have to set the PINPOINT_TRACE_EXCLUSION_URL_PATTERN, PINPOINT_TRACE_EXCLUSION_URL_CACHE_SIZE or trace-exclusion-url{ pattern: 'pattern', 'cache-size': 100} for using excludsion url cache.`)
288+
}
289+
290+
if (Array.isArray(config.traceExclusionUrlPatterns) && Number.isInteger(config.traceExclusionUrlCacheSize)) {
291+
if (config.traceExclusionUrlCacheSize < 100) {
292+
config.traceExclusionUrlCacheSize = 100
293+
}
294+
}
295+
},
296+
validateIds: (config) => {
297+
[{ id: config.agentId, name: 'Agent ID', maxLength: 24, required: true }
298+
, { id: config.applicationName, name: 'Application Name', maxLength: 24, required: true }
299+
// Java PinpointConstants.AGENT_NAME_MAX_LEN = 255
300+
, { id: config.agentName, name: 'Agent Name', maxLength: 255, required: false }
301+
].filter(id => id.id)
302+
.filter(id => {
303+
if (isNaN(id.maxLength)) {
304+
return false
305+
}
306+
307+
if (id.required && typeof id.id !== 'string') {
308+
config.enable = false
309+
log.warn(`You have to set ${id.name}`)
310+
return false
311+
}
312+
313+
if (id.required === false && typeof id.id !== 'string') {
314+
return false
315+
}
316+
317+
const maxLength = id.maxLength
318+
const idRegex = /^[a-zA-Z0-9\\._\\-]+$/
319+
320+
if (id.id.length < 1) {
321+
config.enable = false
322+
log.warn(`You have to set ${id.name}`)
323+
return false
324+
}
325+
326+
if (id.id.length > maxLength) {
327+
config.enable = false
328+
log.warn(`You have to set ${id.name} to less ${maxLength} characters.`)
329+
return false
330+
}
331+
332+
if (!idRegex.test(id.id)) {
333+
config.enable = false
334+
log.warn(`invalidate ${id.name} name with /[a-zA-Z0-9\\._\\-]+/ RegExp`)
335+
return false
336+
}
337+
})
338+
}
339+
}
340+
341+
let configInstance
342+
const getConfig = (json) => {
343+
if (!configInstance) {
344+
configInstance = new ConfigBuilder(json).build()
345+
}
346+
return configInstance
347+
}
348+
349+
const setConfig = (config) => {
350+
if (!(config instanceof Config)) {
351+
throw new TypeError('config must be an instance of Config')
352+
}
353+
354+
configInstance = config
355+
}
356+
357+
const clear = () => configInstance && (configInstance = null)
358+
340359
module.exports = {
341-
getConfig,
342-
clear,
343360
readConfigJson,
344361
readRootConfigFile,
345362
getMainModulePath,
346363
isContainerEnvironment,
347-
initializeConfig,
348-
registerLoadedConfig,
349-
}
364+
ConfigBuilder,
365+
getConfig,
366+
setConfig,
367+
clear
368+
}

lib/context/method-descriptor-builder.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class MethodDescriptorBuilder {
8383
if (this.apiDescriptor) {
8484
return this.apiDescriptor
8585
}
86-
86+
8787
const cacheIds = [this.formattedStringOfCall()]
8888

8989
if (typeof this.fileName === 'string') {

0 commit comments

Comments
 (0)