Skip to content

Commit 1d682c2

Browse files
MSNevdyladan
andauthored
feat(diag-logger): introduce a new global level api.diag for internal diagnostic logging (#1880)
Co-authored-by: Daniel Dyla <[email protected]>
1 parent 000a8ac commit 1d682c2

File tree

20 files changed

+1287
-17
lines changed

20 files changed

+1287
-17
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ package.json.lerna_backup
7878
# VsCode configs
7979
.vscode/
8080

81+
#Visual Studio
82+
.vs/
83+
8184
#IDEA
8285
.idea
8386
*.iml

benchmark/tracer.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const benchmark = require('./benchmark');
44
const opentelemetry = require('../packages/opentelemetry-api');
55
const { BasicTracerProvider, BatchSpanProcessor, InMemorySpanExporter, SimpleSpanProcessor } = require('../packages/opentelemetry-tracing');
66

7-
const logger = new opentelemetry.NoopLogger();
7+
const diagLogger = opentelemetry.createNoopDiagLogger();
88

99
const setups = [
1010
{
@@ -13,7 +13,7 @@ const setups = [
1313
},
1414
{
1515
name: 'BasicTracerProvider',
16-
provider: new BasicTracerProvider({ logger })
16+
provider: new BasicTracerProvider({ logger: diagLogger })
1717
},
1818
{
1919
name: 'BasicTracerProvider with SimpleSpanProcessor',
@@ -63,7 +63,7 @@ for (const setup of setups) {
6363
suite.run({ async: false });
6464
}
6565
function getProvider(processor) {
66-
const provider = new BasicTracerProvider({ logger });
66+
const provider = new BasicTracerProvider({ logger: diagLogger });
6767
provider.addSpanProcessor(processor);
6868
return provider;
6969
}

examples/collector-exporter-node/metrics.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
'use strict';
22

3-
const { ConsoleLogger, LogLevel } = require('@opentelemetry/core');
3+
const { DiagConsoleLogger, DiagLogLevel, diag } = require('@opentelemetry/api');
44
const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');
55
// const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector-grpc');
66
// const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector-proto');
77
const { MeterProvider } = require('@opentelemetry/metrics');
88

9+
diag.setLogger(new DiagConsoleLogger());
10+
diag.setLogLevel(DiagLogLevel.DEBUG);
11+
912
const metricExporter = new CollectorMetricExporter({
1013
serviceName: 'basic-metric-service',
1114
// url: 'http://localhost:55681/v1/metrics',
12-
logger: new ConsoleLogger(LogLevel.DEBUG),
15+
logger: diag,
1316
});
1417

1518
const meter = new MeterProvider({

examples/collector-exporter-node/tracing.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
'use strict';
22

33
const opentelemetry = require('@opentelemetry/api');
4-
// const { ConsoleLogger, LogLevel} = require('@opentelemetry/core');
54
const { BasicTracerProvider, ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing');
65
const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector');
76
// const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-grpc');
87
// const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-proto');
98

9+
// opentelemetry.diag.setLogger(new opentelemetry.DiagConsoleLogger());
10+
// opentelemetry.diag.setLogLevel(opentelemetry.DiagLogLevel.DEBUG);
11+
1012
const exporter = new CollectorTraceExporter({
1113
serviceName: 'basic-service',
12-
// logger: new ConsoleLogger(LogLevel.DEBUG),
1314
// headers: {
1415
// foo: 'bar'
1516
// },

examples/metrics/metrics/observer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22

33
const { MeterProvider } = require('@opentelemetry/metrics');
4-
const { ConsoleLogger, LogLevel } = require('@opentelemetry/core');
4+
const { DiagConsoleLogger, DiagLogLevel, diagLogLevelFilter } = require('@opentelemetry/api');
55
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
66

77
const exporter = new PrometheusExporter(
@@ -61,7 +61,7 @@ meter.createBatchObserver((observerBatchResult) => {
6161
});
6262
}, {
6363
maxTimeoutUpdateMS: 500,
64-
logger: new ConsoleLogger(LogLevel.DEBUG)
64+
logger: diagLogLevelFilter(DiagLogLevel.DEBUG, new DiagConsoleLogger())
6565
},
6666
);
6767

examples/tracer-web/examples/metrics/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
'use strict';
22

3-
const { ConsoleLogger, LogLevel } = require('@opentelemetry/core');
3+
const { DiagConsoleLogger, DiagLogLevel, diagLogLevelFilter } = require('@opentelemetry/api');
44
const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');
55
const { MeterProvider } = require('@opentelemetry/metrics');
66

77
const metricExporter = new CollectorMetricExporter({
88
serviceName: 'basic-metric-service',
9-
logger: new ConsoleLogger(LogLevel.DEBUG),
9+
logger: diagLogLevelFilter(DiagLogLevel.DEBUG, new DiagConsoleLogger()),
1010
});
1111

1212
let interval;
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {
18+
DiagLogger,
19+
DiagLogFunction,
20+
createNoopDiagLogger,
21+
diagLoggerFunctions,
22+
} from '../diag/logger';
23+
import { DiagLogLevel, createLogLevelDiagLogger } from '../diag/logLevel';
24+
import {
25+
API_BACKWARDS_COMPATIBILITY_VERSION,
26+
GLOBAL_DIAG_LOGGER_API_KEY,
27+
makeGetter,
28+
_global,
29+
} from './global-utils';
30+
31+
/** Internal simple Noop Diag API that returns a noop logger and does not allow any changes */
32+
function noopDiagApi(): DiagAPI {
33+
const noopApi = createNoopDiagLogger() as DiagAPI;
34+
35+
noopApi.getLogger = () => noopApi;
36+
noopApi.setLogger = noopApi.getLogger;
37+
noopApi.setLogLevel = () => {};
38+
39+
return noopApi;
40+
}
41+
42+
/**
43+
* Singleton object which represents the entry point to the OpenTelemetry internal
44+
* diagnostic API
45+
*/
46+
export class DiagAPI implements DiagLogger {
47+
/** Get the singleton instance of the DiagAPI API */
48+
public static instance(): DiagAPI {
49+
let theInst = null;
50+
if (_global[GLOBAL_DIAG_LOGGER_API_KEY]) {
51+
// Looks like a previous instance was set, so try and fetch it
52+
theInst = _global[GLOBAL_DIAG_LOGGER_API_KEY]?.(
53+
API_BACKWARDS_COMPATIBILITY_VERSION
54+
) as DiagAPI;
55+
}
56+
57+
if (!theInst) {
58+
theInst = new DiagAPI();
59+
_global[GLOBAL_DIAG_LOGGER_API_KEY] = makeGetter(
60+
API_BACKWARDS_COMPATIBILITY_VERSION,
61+
theInst,
62+
noopDiagApi()
63+
);
64+
}
65+
66+
return theInst;
67+
}
68+
69+
/**
70+
* Private internal constructor
71+
* @private
72+
*/
73+
private constructor() {
74+
let _logLevel: DiagLogLevel = DiagLogLevel.INFO;
75+
let _filteredLogger: DiagLogger | null;
76+
let _logger: DiagLogger = createNoopDiagLogger();
77+
78+
function _logProxy(funcName: keyof DiagLogger): DiagLogFunction {
79+
return function () {
80+
const orgArguments = arguments as unknown;
81+
const theLogger = _filteredLogger || _logger;
82+
const theFunc = theLogger[funcName];
83+
if (typeof theFunc === 'function') {
84+
return theFunc.apply(
85+
theLogger,
86+
orgArguments as Parameters<DiagLogFunction>
87+
);
88+
}
89+
};
90+
}
91+
92+
// Using self local variable for minification purposes as 'this' cannot be minified
93+
const self = this;
94+
95+
// DiagAPI specific functions
96+
97+
self.getLogger = (): DiagLogger => {
98+
// Return itself if no existing logger is defined (defaults effectively to a Noop)
99+
return _logger;
100+
};
101+
102+
self.setLogger = (logger: DiagLogger): DiagLogger => {
103+
const prevLogger = _logger;
104+
if (prevLogger !== logger && logger !== self) {
105+
// Simple special case to avoid any possible infinite recursion on the logging functions
106+
_logger = logger || createNoopDiagLogger();
107+
_filteredLogger = createLogLevelDiagLogger(_logLevel, _logger);
108+
}
109+
110+
return prevLogger;
111+
};
112+
113+
self.setLogLevel = (maxLogLevel: DiagLogLevel) => {
114+
if (maxLogLevel !== _logLevel) {
115+
_logLevel = maxLogLevel;
116+
if (_logger) {
117+
_filteredLogger = createLogLevelDiagLogger(maxLogLevel, _logger);
118+
}
119+
}
120+
};
121+
122+
for (let i = 0; i < diagLoggerFunctions.length; i++) {
123+
const name = diagLoggerFunctions[i];
124+
self[name] = _logProxy(name);
125+
}
126+
}
127+
128+
/**
129+
* Return the currently configured logger instance, if no logger has been configured
130+
* it will return itself so any log level filtering will still be applied in this case.
131+
*/
132+
public getLogger!: () => DiagLogger;
133+
134+
/**
135+
* Set the DiagLogger instance
136+
* @param logger - The DiagLogger instance to set as the default logger
137+
* @returns The previously registered DiagLogger
138+
*/
139+
public setLogger!: (logger: DiagLogger) => DiagLogger;
140+
141+
/** Set the default maximum diagnostic logging level */
142+
public setLogLevel!: (maxLogLevel: DiagLogLevel) => void;
143+
144+
// DiagLogger implementation
145+
public verbose!: DiagLogFunction;
146+
public debug!: DiagLogFunction;
147+
public info!: DiagLogFunction;
148+
public warn!: DiagLogFunction;
149+
public startupInfo!: DiagLogFunction;
150+
public error!: DiagLogFunction;
151+
public critical!: DiagLogFunction;
152+
public terminal!: DiagLogFunction;
153+
}

packages/opentelemetry-api/src/api/global-utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { ContextManager } from '@opentelemetry/context-base';
1818
import { TextMapPropagator } from '../context/propagation/TextMapPropagator';
1919
import { TracerProvider } from '../trace/tracer_provider';
2020
import { _globalThis } from '../platform';
21+
import { DiagAPI } from '../api/diag';
2122

2223
export const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for(
2324
'io.opentelemetry.js.api.context'
@@ -28,11 +29,16 @@ export const GLOBAL_PROPAGATION_API_KEY = Symbol.for(
2829
);
2930
export const GLOBAL_TRACE_API_KEY = Symbol.for('io.opentelemetry.js.api.trace');
3031

32+
export const GLOBAL_DIAG_LOGGER_API_KEY = Symbol.for(
33+
'io.opentelemetry.js.api.diag'
34+
);
35+
3136
type Get<T> = (version: number) => T;
3237
type OtelGlobal = Partial<{
3338
[GLOBAL_CONTEXT_MANAGER_API_KEY]: Get<ContextManager>;
3439
[GLOBAL_PROPAGATION_API_KEY]: Get<TextMapPropagator>;
3540
[GLOBAL_TRACE_API_KEY]: Get<TracerProvider>;
41+
[GLOBAL_DIAG_LOGGER_API_KEY]: Get<DiagAPI>;
3642
}>;
3743

3844
export const _global = _globalThis as OtelGlobal;

packages/opentelemetry-api/src/common/Logger.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
export type LogFunction = (message: string, ...args: unknown[]) => void;
1818

19-
/** Defines a logger interface. */
19+
/** Defines a logger interface.
20+
* @deprecated This interface will be removed prior to v1.0, use the api.diag
21+
* @see {@link DiagLogger} and {@link DiagAPI}
22+
*/
2023
export interface Logger {
2124
error: LogFunction;
2225
warn: LogFunction;

0 commit comments

Comments
 (0)