microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
fedimser/qmem

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/npm/qsharp/src/log.ts

112lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4// Logging infrastructure for JavaScript environments (e.g. browser and node.js)
5//
6// Ideally this should be the only module to have global side effects and run code
7// on module load (i.e. other modules should consist almost entirely of declarations
8// and exports at the top level), which means it is configurable and usable from
9// the host environment after import resolution and before other logic runs.
10
11declare global {
12 // Align with VS Code names (but not level numbers)
13 // 0 = off
14 // 1 = error
15 // 2 = warn
16 // 3 = info
17 // 4 = debug (called 'verbose' in VS Code)
18 // 5 = trace
19 // Note this also aligns with the Rust log crate macros/levels
20 // See https://docs.rs/log/latest/log/
21 var qscLog: typeof log;
22 var qscGitHash: string;
23}
24
25export type LogLevel = "off" | "error" | "warn" | "info" | "debug" | "trace";
26export type TelemetryEvent = { id: string; data?: any };
27export type TelemetryCollector = (event: TelemetryEvent) => void;
28
29let telemetryCollector: TelemetryCollector | null = null;
30const levels = ["off", "error", "warn", "info", "debug", "trace"];
31let logLevel = 0;
32
33export const log = {
34 setLogLevel(level: LogLevel | number) {
35 if (typeof level === "string") {
36 // Convert to number
37 const lowerLevel = level.toLowerCase();
38 let newLevel = 0;
39 levels.forEach((name, idx) => {
40 if (name === lowerLevel) newLevel = idx;
41 });
42 logLevel = newLevel;
43 } else {
44 logLevel = level;
45 }
46 this.onLevelChanged?.(logLevel);
47 },
48 onLevelChanged: null as ((level: number) => void) | null,
49 getLogLevel(): number {
50 return logLevel;
51 },
52 error(...args: any) {
53 if (logLevel >= 1) console.error(...args);
54 },
55 warn(...args: any) {
56 if (logLevel >= 2) console.warn(...args);
57 },
58 info(...args: any) {
59 if (logLevel >= 3) console.info(...args);
60 },
61 debug(...args: any) {
62 if (logLevel >= 4) console.debug(...args);
63 },
64 trace(...args: any) {
65 // console.trace in JavaScript just writes a stack trace at info level, so use 'debug'
66 if (logLevel >= 5) console.debug(...args);
67 },
68 never(val: never) {
69 // Utility function to ensure exhaustive type checking. See https://stackoverflow.com/a/39419171
70 log.error("Exhaustive type checking didn't account for: %o", val);
71 },
72 /**
73 * @param level - A number indicating severity: 1 = Error, 2 = Warn, 3 = Info, 4 = Debug, 5 = Trace
74 * @param target - The area or component sending the message, e.g. "parser" (useful for filtering)
75 * @param args - The format string and args to log, e.g. ["Index of %s is %i", str, index]
76 */
77 logWithLevel(level: number, target: string, ...args: any) {
78 const [firstArg, ...trailingArgs] = args;
79 const outArgs = [`[${target || ""}] ${firstArg}`, ...trailingArgs];
80 switch (level) {
81 case 1:
82 log.error(...outArgs);
83 break;
84 case 2:
85 log.warn(...outArgs);
86 break;
87 case 3:
88 log.info(...outArgs);
89 break;
90 case 4:
91 log.debug(...outArgs);
92 break;
93 case 5:
94 log.trace(...outArgs);
95 break;
96 default:
97 log.error("Invalid logLevel: ", level);
98 }
99 },
100 setTelemetryCollector(handler: TelemetryCollector) {
101 telemetryCollector = handler;
102 },
103 logTelemetry(event: { id: string; data?: any }) {
104 telemetryCollector?.(event);
105 },
106 isTelemetryEnabled() {
107 return !!telemetryCollector;
108 },
109};
110
111// Enable globally for easy interaction and debugging in live environments
112globalThis.qscLog = log;
113