-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathindex.js
More file actions
242 lines (203 loc) · 8.72 KB
/
index.js
File metadata and controls
242 lines (203 loc) · 8.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*
* (c) Copyright IBM Corp. 2021
* (c) Copyright Instana Inc. and contributors 2019
*/
'use strict';
const { esm, nodeJsVersionCheck } = require('@instana/core/src/util');
const { isProcessAvailable } = require('@instana/core/src/util/moduleAvailable');
if (!isProcessAvailable()) {
// eslint-disable-next-line no-console
console.error('The Node.js core module process is not available. This process will not be monitored by Instana.');
module.exports = function noOp() {};
// ESM default exports for TS
module.exports.default = function noOp() {};
module.exports = function noOp() {};
// @ts-ignore TS1108 (return can only be used within a function body)
return;
}
if (nodeJsVersionCheck.isNodeJsTooOld()) {
// eslint-disable-next-line no-console
console.error(
// eslint-disable-next-line max-len
`The package @instana/collector requires at least Node.js ${nodeJsVersionCheck.minimumNodeJsVersion} but this process is ` +
`running on Node.js ${process.version}. This process will not be monitored by Instana. For more information, ` +
// eslint-disable-next-line max-len
'see: https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-support-information#breaking-changes-in-nodejs-collector-upgrade'
);
// ESM default exports for TS
module.exports.default = function noOp() {};
module.exports = function noOp() {};
// @ts-ignore TS1108 (return can only be used within a function body)
return;
}
// v18.19 and above usage of --experimental-loader flag no longer supported
// TODO: Remove error log in the next major release(v6)
if (esm.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
"Node.js 18.19.0 and later no longer support the '--experimental-loader' flag for ESM. " +
`Your current version is ${process.version}. To ensure tracing by Instana, ` +
"please use the '--import' flag instead. For more information, refer to the Instana documentation: " +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
module.exports.default = function noOp() {};
module.exports = function noOp() {};
// @ts-ignore TS1108
return;
}
// This loader worked with '--experimental-loader' in Node.js versions below 18.19.
// TODO: Remove 'esm-loader.mjs' file and this log in the next major release (v6).
if (esm.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Importing 'esm-loader.mjs' is not supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"Use 'esm-register.mjs' with '--import' to enable tracing. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
module.exports.default = function noOp() {};
module.exports = function noOp() {};
// @ts-ignore TS1108
return;
}
let isMainThread = true;
try {
isMainThread = require('worker_threads').isMainThread;
} catch (err) {
// Worker threads are not available, so we know that this is the main thread.
}
// Check if worker threads should be disabled via environment variable.
// Disabling worker threads may be necessary in environments where
// multi-threading causes issues or monitoring of worker threads is not required.
const disableWorkerThreads = process.env.INSTANA_DISABLE_WORKER_THREADS?.toLowerCase() === 'true';
if (disableWorkerThreads && !isMainThread) {
// eslint-disable-next-line no-console
console.warn(
'Worker threads are disabled via INSTANA_DISABLE_WORKER_THREADS. ' +
'This worker thread will not be monitored by Instana.'
);
module.exports = function noOp() {};
module.exports.default = function noOp() {};
// @ts-ignore
return;
}
const path = require('path');
const instanaNodeJsCore = require('@instana/core');
const instanaSharedMetrics = require('@instana/shared-metrics');
require('./tracing'); // load additional instrumentations
const log = require('./logger');
const normalizeConfig = require('./util/normalizeConfig');
const experimental = require('./experimental');
// NOTE: Default collector logger && config for cases like `preinit`.
const logger = log.init();
instanaNodeJsCore.coreConfig.init(logger);
/** @type {import('./types/collector').CollectorConfig} */
let config = instanaNodeJsCore.coreConfig.normalize();
/** @type {import('./agentConnection')} */
let agentConnection;
/**
* @param {import('./types/collector').CollectorConfig} [userConfig]
*/
function init(userConfig = {}) {
// @ts-ignore: Property '__INSTANA_INITIALIZED' does not exist on type global
if (global.__INSTANA_INITIALIZED) {
// Prevent initializing @instana/collector multiple times for the same process: @instana/collector has already been
// initialized, potentially from a different installation of @instana/collector somewhere else in the file system.
// Find that module in the require cache and return its exports (this is necessary to make sure calls to our API
// work as expected).
let collectorIndexCacheKey = Object.keys(require.cache).find(
cacheKey => cacheKey.indexOf('/@instana/collector/src/index.js') >= 0
);
// Requiring the collector package twice in the test package using a relative path such as `../../..`
if (process.env.NODE_ENV === 'test') {
collectorIndexCacheKey = Object.keys(require.cache).find(
cacheKey => cacheKey.indexOf('collector/src/index.js') >= 0
);
}
if (collectorIndexCacheKey) {
process?.send?.('instana.collector.initialized');
return require.cache[collectorIndexCacheKey].exports;
} else {
// eslint-disable-next-line no-console
console.error(
"Warning: Instana has already been initialized but the module @instana/collector is not present in Node.js' " +
'module cache. The Instana API will not be available.'
);
return init;
}
}
// @ts-ignore: Property '__INSTANA_INITIALIZED' does not exist on type global
global.__INSTANA_INITIALIZED = true;
// CASE: reinit logger if custom logger or log level is provided.
if (userConfig.logger || userConfig.level) {
log.init(userConfig);
}
const finalCollectorConfig = normalizeConfig(userConfig);
config = instanaNodeJsCore.coreConfig.normalize({
userConfig,
finalConfigBase: finalCollectorConfig
});
agentConnection = require('./agentConnection');
const agentOpts = require('./agent/opts');
const pidStore = require('./pidStore');
const uncaught = require('./uncaught');
const announceCycle = require('./announceCycle');
const metrics = require('./metrics');
log.setDownstreamConnection(agentConnection);
pidStore.init(config);
agentOpts.init(config);
agentConnection.init(config, pidStore);
announceCycle.init(config, pidStore);
instanaNodeJsCore.init(config, agentConnection, pidStore);
if (isMainThread) {
uncaught.init(config, agentConnection, pidStore);
metrics.init(config, pidStore);
}
logger.info(`@instana/collector module version: ${require(path.join(__dirname, '..', 'package.json')).version}`);
announceCycle.start();
return init;
}
init.currentSpan = function getHandleForCurrentSpan() {
return instanaNodeJsCore.tracing.getHandleForCurrentSpan();
};
init.isTracing = function isTracing() {
return instanaNodeJsCore.tracing.getCls() ? instanaNodeJsCore.tracing.getCls().isTracing() : false;
};
init.isConnected = function isConnected() {
return agentConnection && agentConnection.isConnected();
};
/**
* Keep in mind:
* Instana logs might appear in the internal log level for a very short time
* if you set a custom logger with a different log level. That is because "setLogger"
* is called after the initialization of the collector.
*
* const instana = require('@instana/collector')();
* const pino = require('pino')
* instana.setLogger(pinoLogger)
*
* Setting the **same** log level in the custom logger and the collector logger
* will prevent this behavior.
*
* @param {import('@instana/core/src/core').GenericLogger} _logger
*/
init.setLogger = function setLogger(_logger) {
// NOTE: Override our default logger with customer's logger
log.init({ logger: _logger });
};
init.core = instanaNodeJsCore;
init.sharedMetrics = instanaSharedMetrics;
init.experimental = experimental;
init.opentracing = instanaNodeJsCore.tracing.opentracing;
init.sdk = instanaNodeJsCore.tracing.sdk;
if (process.env.INSTANA_IMMEDIATE_INIT != null && process.env.INSTANA_IMMEDIATE_INIT.toLowerCase() === 'true') {
init();
} else if (
process.env.INSTANA_EARLY_INSTRUMENTATION != null &&
process.env.INSTANA_EARLY_INSTRUMENTATION.toLowerCase() === 'true'
) {
instanaNodeJsCore.preInit(config);
}
module.exports = init;
module.exports.default = init;