Skip to content

Commit 7b1c5b3

Browse files
committed
feat(diag-logger): introduce a new global level api.diag for internal diagnostic logging (Part 1) #1877
1 parent 65277da commit 7b1c5b3

File tree

20 files changed

+2491
-21
lines changed

20 files changed

+2491
-21
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ package.json.lerna_backup
7777
# VsCode configs
7878
.vscode/
7979

80+
#Visual Studio
81+
.vs/
82+
8083
#IDEA
8184
.idea
8285
*.iml

benchmark/tracer.js

+3-3
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.noopDiagLogger();
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

+5-2
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

+3-2
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

+2-2
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

+2-2
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;
+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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 { DiagLogger, DiagLogFunction, noopDiagLogger } from '../diag/logger';
18+
import { DiagLogLevel, diagLogLevelFilter } from '../diag/logLevel';
19+
import {
20+
API_BACKWARDS_COMPATIBILITY_VERSION,
21+
GLOBAL_DIAG_LOGGER_API_KEY,
22+
makeGetter,
23+
_global,
24+
} from './global-utils';
25+
26+
/** Internal simple Noop Diag API that returns a noop logger and does not allow any changes */
27+
function noopDiagApi(): DiagAPI {
28+
const noopApi = noopDiagLogger() as DiagAPI;
29+
30+
noopApi.getLogger = () => noopApi;
31+
noopApi.setLogger = noopApi.getLogger;
32+
noopApi.setLogLevel = () => {};
33+
34+
return noopApi;
35+
}
36+
37+
/**
38+
* Singleton object which represents the entry point to the OpenTelemetry internal
39+
* diagnostic API
40+
*/
41+
export class DiagAPI implements DiagLogger {
42+
/** Get the singleton instance of the DiagAPI API */
43+
public static inst(): DiagAPI {
44+
let theInst = null;
45+
if (_global[GLOBAL_DIAG_LOGGER_API_KEY]) {
46+
// Looks like a previous instance was set, so try and fetch it
47+
theInst = _global[GLOBAL_DIAG_LOGGER_API_KEY]?.(
48+
API_BACKWARDS_COMPATIBILITY_VERSION
49+
) as DiagAPI;
50+
}
51+
52+
if (!theInst) {
53+
theInst = new DiagAPI();
54+
_global[GLOBAL_DIAG_LOGGER_API_KEY] = makeGetter(
55+
API_BACKWARDS_COMPATIBILITY_VERSION,
56+
theInst,
57+
noopDiagApi()
58+
);
59+
}
60+
61+
return theInst;
62+
}
63+
64+
/** Private internal constructor
65+
* @private */
66+
private constructor() {
67+
let _logLevel: DiagLogLevel = DiagLogLevel.INFO;
68+
let _filteredLogger: DiagLogger | null;
69+
let _logger: DiagLogger = noopDiagLogger();
70+
71+
function _logProxy(funcName: keyof DiagLogger): DiagLogFunction {
72+
return function () {
73+
const orgArguments = arguments as unknown;
74+
const theLogger = _filteredLogger || _logger;
75+
const theFunc = theLogger[funcName];
76+
if (theFunc && typeof theFunc === 'function') {
77+
return theFunc.apply(
78+
theLogger,
79+
orgArguments as Parameters<DiagLogFunction>
80+
);
81+
}
82+
};
83+
}
84+
85+
// Using self local variable for minification purposes as 'this' cannot be minified
86+
const self = this;
87+
88+
// DiagAPI specific functions
89+
90+
self.getLogger = (): DiagLogger => {
91+
// Return itself if no existing logger is defined (defaults effectively to a Noop)
92+
return _logger;
93+
};
94+
95+
self.setLogger = (logger: DiagLogger): DiagLogger => {
96+
const prevLogger = _logger;
97+
if (prevLogger !== logger && logger !== self) {
98+
// Simple special case to avoid any possible infinite recursion on the logging functions
99+
_logger = logger || noopDiagLogger();
100+
_filteredLogger = diagLogLevelFilter(_logLevel, _logger);
101+
}
102+
103+
return prevLogger;
104+
};
105+
106+
self.setLogLevel = (maxLogLevel: DiagLogLevel) => {
107+
if (maxLogLevel !== _logLevel) {
108+
_logLevel = maxLogLevel;
109+
if (_logger) {
110+
_filteredLogger = diagLogLevelFilter(maxLogLevel, _logger);
111+
}
112+
}
113+
};
114+
115+
// DiagLogger implementation
116+
const theFuncs: Array<keyof DiagLogger> = [
117+
'trace',
118+
'debug',
119+
'info',
120+
'warn',
121+
'error',
122+
'critical',
123+
'terminal',
124+
'forcedInfo',
125+
];
126+
for (let lp = 0; lp < theFuncs.length; lp++) {
127+
const name = theFuncs[lp];
128+
self[name] = _logProxy(name);
129+
}
130+
}
131+
132+
/** Return the currently configured logger instance, if no logger has been configured
133+
* it will return itself so any log level filtering will still be applied in this case.
134+
*/
135+
public getLogger!: () => DiagLogger;
136+
137+
/** Set the DiagLogger instance
138+
* @param logger - The DiagLogger instance to set as the default logger
139+
* @returns The previously registered DiagLogger
140+
*/
141+
public setLogger!: (logger: DiagLogger) => DiagLogger;
142+
143+
/** Set the default maximum diagnostic logging level */
144+
public setLogLevel!: (maxLogLevel: DiagLogLevel) => void;
145+
146+
// DiagLogger implementation
147+
public trace!: DiagLogFunction;
148+
public debug!: DiagLogFunction;
149+
public info!: DiagLogFunction;
150+
public warn!: DiagLogFunction;
151+
public error!: DiagLogFunction;
152+
public critical!: DiagLogFunction;
153+
public terminal!: DiagLogFunction;
154+
155+
public forcedInfo!: DiagLogFunction;
156+
}

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

+6
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

+4-1
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)