Skip to content

Commit a7418e4

Browse files
committed
feat(logging): use OutputChannel log level
Problem: Q extension may show error message: [amazonwebservices.amazon-q-vscode]: Cannot register 'aws.logLevel'. This property is already registered. Solution: - Remove the `aws.logLevel` setting from both Toolkit and Q. - Let the OutputChannel drive the loglevel. - For very old vscode (older than 1.74), default to "debug" log-level. microsoft/vscode@2cd8ea2
1 parent 716453c commit a7418e4

File tree

10 files changed

+69
-146
lines changed

10 files changed

+69
-146
lines changed

CONTRIBUTING.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,14 @@ The `aws.dev.forceDevMode` setting enables or disables Toolkit "dev mode". Witho
315315
316316
### Logging
317317
318-
- Use the `aws.dev.logfile` setting to set the logfile path to a fixed location, so you can easily
319-
follow and filter the logfile using shell tools like `tail` and `grep`. For example in
320-
settings.json,
318+
- Use `getLogger()` to log debugging messages, warnings, etc.
319+
- Example: `getLogger().error('topic: widget failed: %O', { foo: 'bar', baz: 42 })`
320+
- Log messages are written to the extension Output channel, which you can view in vscode by visiting the "Output" panel and selecting `AWS Toolkit Logs` or `Amazon Q Logs`.
321+
- While viewing the Output channel (`AWS Toolkit Logs` or `Amazon Q Logs`) in vscode:
322+
- Click the "gear" icon to [select a log level](https://github.com/aws/aws-toolkit-vscode/pull/4859) ("Debug", "Info", "Error", …).
323+
- Click the "..." icon to open the log file.
324+
- Use the `aws.dev.logfile` setting to set the logfile path to a fixed location, so you can follow
325+
and filter logs using shell tools like `tail` and `grep`. For example in settings.json,
321326
```
322327
"aws.dev.logfile": "~/awstoolkit.log",
323328
```
@@ -328,7 +333,6 @@ The `aws.dev.forceDevMode` setting enables or disables Toolkit "dev mode". Witho
328333
- Use the `AWS (Developer): Watch Logs` command to watch and filter Toolkit logs (including
329334
telemetry) in VSCode.
330335
- Only available if you enabled "dev mode" (`aws.dev.forceDevMode` setting, see above).
331-
- Sets `aws.logLevel` to "debug".
332336
- Enter text in the Debug Console filter box to show only log messages with that text. <br/>
333337
<img src="./docs/images/debug-console-filter.png" alt="VSCode Debug Console" width="320"/>
334338

packages/amazonq/package.json

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,30 +60,6 @@
6060
}
6161
},
6262
"properties": {
63-
"aws.logLevel": {
64-
"type": "string",
65-
"default": "debug",
66-
"enum": [
67-
"error",
68-
"warn",
69-
"info",
70-
"verbose",
71-
"debug"
72-
],
73-
"enumDescriptions": [
74-
"Errors Only",
75-
"Errors and Warnings",
76-
"Errors, Warnings, and Info",
77-
"Errors, Warnings, Info, and Verbose",
78-
"Errors, Warnings, Info, Verbose, and Debug"
79-
],
80-
"markdownDescription": "%AWS.configuration.description.logLevel%",
81-
"cloud9": {
82-
"cn": {
83-
"markdownDescription": "%AWS.configuration.description.logLevel.cn%"
84-
}
85-
}
86-
},
8763
"amazonQ.telemetry": {
8864
"type": "boolean",
8965
"default": true,

packages/core/package.json

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -90,30 +90,6 @@
9090
"default": false,
9191
"markdownDescription": "%AWS.configuration.description.samcli.legacyDeploy%"
9292
},
93-
"aws.logLevel": {
94-
"type": "string",
95-
"default": "debug",
96-
"enum": [
97-
"error",
98-
"warn",
99-
"info",
100-
"verbose",
101-
"debug"
102-
],
103-
"enumDescriptions": [
104-
"Errors Only",
105-
"Errors and Warnings",
106-
"Errors, Warnings, and Info",
107-
"Errors, Warnings, Info, and Verbose",
108-
"Errors, Warnings, Info, Verbose, and Debug"
109-
],
110-
"markdownDescription": "%AWS.configuration.description.logLevel%",
111-
"cloud9": {
112-
"cn": {
113-
"markdownDescription": "%AWS.configuration.description.logLevel.cn%"
114-
}
115-
}
116-
},
11793
"aws.telemetry": {
11894
"type": "boolean",
11995
"default": true,

packages/core/package.nls.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
"AWS.configuration.profileDescription": "The name of the credential profile to obtain credentials from.",
1010
"AWS.configuration.description.lambda.recentlyUploaded": "Recently selected Lambda upload targets.",
1111
"AWS.configuration.description.ecs.openTerminalCommand": "The command to run when starting a new interactive terminal session.",
12-
"AWS.configuration.description.logLevel": "AWS IDE Extensions log level (changes reflected on restart)",
13-
"AWS.configuration.description.logLevel.cn": "The Amazon Toolkit's log level (changes reflected on restart)",
1412
"AWS.configuration.description.iot.maxItemsPerPage": "Controls how many IoT Things, Certificates, or Policies are listed before showing a node to `Load More...`.",
1513
"AWS.configuration.description.s3.maxItemsPerPage": "Controls how many S3 items are listed before showing a node to `Load More...`.\nThis corresponds to the `MaxKeys` requested in a single call to S3. [Learn More](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html#AmazonS3-ListObjectsV2-response-MaxKeys)",
1614
"AWS.configuration.description.samcli.lambdaTimeout": "Maximum time (in milliseconds) to wait for SAM output while starting a Local Lambda session",

packages/core/src/codewhisperer/commands/startSecurityScan.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export const stopScanButton = localize('aws.codewhisperer.stopscan', 'Stop Scan'
4949
const getLogOutputChan = once(() => {
5050
const codeScanOutpuChan = vscode.window.createOutputChannel('Amazon Q Security Scan Logs')
5151
const codeScanLogger = makeLogger({
52+
logLevel: 'info',
5253
outputChannels: [codeScanOutpuChan],
5354
})
5455
return [codeScanLogger, codeScanOutpuChan] as const

packages/core/src/shared/logger/activation.ts

Lines changed: 33 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55

66
import * as vscode from 'vscode'
77
import { Logger, LogLevel, getLogger } from '.'
8-
import { setLogger } from './logger'
8+
import { fromVscodeLogLevel, setLogger } from './logger'
99
import { WinstonToolkitLogger } from './winstonToolkitLogger'
1010
import { Settings } from '../settings'
1111
import { Logging } from './commands'
1212
import { resolvePath } from '../utilities/pathUtils'
1313
import { fsCommon } from '../../srcShared/fs'
14-
import globals, { isWeb } from '../extensionGlobals'
15-
16-
export const defaultLogLevel: LogLevel = 'debug'
14+
import { isWeb } from '../extensionGlobals'
1715

1816
/**
1917
* Activate Logger functionality for the extension.
@@ -27,43 +25,41 @@ export async function activate(
2725
const settings = Settings.instance.getSection('aws')
2826
const devLogfile = settings.get('dev.logfile', '')
2927
const logUri = devLogfile ? vscode.Uri.file(resolvePath(devLogfile)) : undefined
28+
const chanLogLevel = fromVscodeLogLevel(logChannel.logLevel)
3029

3130
await fsCommon.mkdir(extensionContext.logUri)
3231

33-
const mainLogger = makeLogger(
34-
{
35-
logPaths: logUri ? [logUri] : undefined,
36-
outputChannels: [logChannel],
37-
useConsoleLog: isWeb(),
38-
},
39-
extensionContext.subscriptions
40-
)
32+
const mainLogger = makeLogger({
33+
logLevel: chanLogLevel,
34+
logPaths: logUri ? [logUri] : undefined,
35+
outputChannels: [logChannel],
36+
useConsoleLog: isWeb(),
37+
})
38+
logChannel.onDidChangeLogLevel?.(logLevel => {
39+
const newLogLevel = fromVscodeLogLevel(logLevel)
40+
mainLogger.setLogLevel(newLogLevel) // Also logs a message.
41+
})
4142

4243
setLogger(mainLogger)
43-
getLogger().info(`log level: ${getLogLevel()}`)
44+
getLogger().info(`Log level: ${chanLogLevel}`)
4445

4546
// Logs to "AWS Toolkit" output channel.
4647
setLogger(
47-
makeLogger(
48-
{
49-
logPaths: logUri ? [logUri] : undefined,
50-
outputChannels: [outputChannel, logChannel],
51-
},
52-
extensionContext.subscriptions
53-
),
48+
makeLogger({
49+
logLevel: chanLogLevel,
50+
logPaths: logUri ? [logUri] : undefined,
51+
outputChannels: [outputChannel, logChannel],
52+
}),
5453
'channel'
5554
)
5655

5756
// Logs to vscode Debug Console.
5857
setLogger(
59-
makeLogger(
60-
{
61-
staticLogLevel: 'debug',
62-
outputChannels: [outputChannel, logChannel],
63-
useDebugConsole: true,
64-
},
65-
extensionContext.subscriptions
66-
),
58+
makeLogger({
59+
logLevel: chanLogLevel,
60+
outputChannels: [outputChannel, logChannel],
61+
useDebugConsole: true,
62+
}),
6763
'debugConsole'
6864
)
6965

@@ -75,25 +71,20 @@ export async function activate(
7571

7672
/**
7773
* Creates a logger off of specified params
78-
* @param opts Specified parameters, all optional:
79-
* @param opts.staticLogLevel Static log level, overriding config value. Will persist overridden config value even if the config value changes.
74+
* @param opts.logLevel Log messages at or above this level
8075
* @param opts.logPaths Array of paths to output log entries to
8176
* @param opts.outputChannels Array of output channels to log entries to
8277
* @param opts.useDebugConsole If true, outputs log entries to `vscode.debug.activeDebugConsole`
8378
* @param opts.useConsoleLog If true, outputs log entries to the nodejs or browser devtools console.
84-
* @param disposables Array of disposables to add a subscription to
8579
*/
86-
export function makeLogger(
87-
opts: {
88-
staticLogLevel?: LogLevel
89-
logPaths?: vscode.Uri[]
90-
outputChannels?: vscode.OutputChannel[]
91-
useDebugConsole?: boolean
92-
useConsoleLog?: boolean
93-
},
94-
disposables?: vscode.Disposable[]
95-
): Logger {
96-
const logger = new WinstonToolkitLogger(opts.staticLogLevel ?? getLogLevel())
80+
export function makeLogger(opts: {
81+
logLevel: LogLevel
82+
logPaths?: vscode.Uri[]
83+
outputChannels?: vscode.OutputChannel[]
84+
useDebugConsole?: boolean
85+
useConsoleLog?: boolean
86+
}): Logger {
87+
const logger = new WinstonToolkitLogger(opts.logLevel)
9788
// debug console can show ANSI colors, output channels can not
9889
const stripAnsi = opts.useDebugConsole ?? false
9990
for (const logPath of opts.logPaths ?? []) {
@@ -109,23 +100,5 @@ export function makeLogger(
109100
logger.logToConsole()
110101
}
111102

112-
if (!opts.staticLogLevel) {
113-
vscode.workspace.onDidChangeConfiguration(
114-
configurationChangeEvent => {
115-
if (configurationChangeEvent.affectsConfiguration('aws.logLevel')) {
116-
const newLogLevel = getLogLevel()
117-
logger.setLogLevel(newLogLevel)
118-
}
119-
},
120-
undefined,
121-
disposables
122-
)
123-
}
124-
125103
return logger
126104
}
127-
128-
function getLogLevel(): LogLevel {
129-
const configuration = Settings.instance.getSection('aws')
130-
return configuration.get(`${globals.contextPrefix}logLevel`, defaultLogLevel)
131-
}

packages/core/src/shared/logger/logger.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { Uri } from 'vscode'
6+
import * as vscode from 'vscode'
77
import globals from '../extensionGlobals'
88

99
const toolkitLoggers: {
@@ -26,7 +26,7 @@ export interface Logger {
2626
setLogLevel(logLevel: LogLevel): void
2727
/** Returns true if the given log level is being logged. */
2828
logLevelEnabled(logLevel: LogLevel): boolean
29-
getLogById(logID: number, file: Uri): string | undefined
29+
getLogById(logID: number, file: vscode.Uri): string | undefined
3030
/** HACK: Enables logging to vscode Debug Console. */
3131
enableDebugConsole(): void
3232
}
@@ -48,6 +48,27 @@ const logLevels = new Map<LogLevel, number>([
4848

4949
export type LogLevel = 'error' | 'warn' | 'info' | 'verbose' | 'debug'
5050

51+
export function fromVscodeLogLevel(logLevel: vscode.LogLevel): LogLevel {
52+
if (!vscode.LogLevel) {
53+
// vscode version <= 1.73
54+
return 'info'
55+
}
56+
57+
switch (logLevel) {
58+
case vscode.LogLevel.Trace:
59+
case vscode.LogLevel.Debug:
60+
return 'debug'
61+
case vscode.LogLevel.Info:
62+
return 'info'
63+
case vscode.LogLevel.Warning:
64+
return 'warn'
65+
case vscode.LogLevel.Error:
66+
case vscode.LogLevel.Off:
67+
default:
68+
return 'error'
69+
}
70+
}
71+
5172
/**
5273
* Compares log levels.
5374
*
@@ -96,7 +117,7 @@ export class NullLogger implements Logger {
96117
public error(message: string | Error, ...meta: any[]): number {
97118
return 0
98119
}
99-
public getLogById(logID: number, file: Uri): string | undefined {
120+
public getLogById(logID: number, file: vscode.Uri): string | undefined {
100121
return undefined
101122
}
102123
public enableDebugConsole(): void {}
@@ -131,7 +152,7 @@ export class ConsoleLogger implements Logger {
131152
console.error(message, ...meta)
132153
return 0
133154
}
134-
public getLogById(logID: number, file: Uri): string | undefined {
155+
public getLogById(logID: number, file: vscode.Uri): string | undefined {
135156
return undefined
136157
}
137158
public enableDebugConsole(): void {}

packages/core/src/shared/logger/outputChannelTransport.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,7 @@ export class OutputChannelTransport extends Transport {
6464
} else if (loglevel === 'warn') {
6565
c.warn(msg)
6666
} else if (loglevel === 'debug' || loglevel === 'verbose') {
67-
// XXX: `vscode.LogOutputChannel` loglevel is currently readonly:
68-
// https://github.com/microsoft/vscode/issues/170450
69-
// https://github.com/PowerShell/vscode-powershell/issues/4441
70-
// So debug() will just drop messages unless the user configures vscode (via
71-
// `code --log …` or `.vscode/argv.json` https://stackoverflow.com/a/77257398/152142).
72-
// Use info() until vscode adds a way to set the loglevel.
73-
c.info(msg)
67+
c.debug(msg)
7468
} else {
7569
c.info(msg)
7670
}

packages/core/src/test/shared/logger/activation.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('makeLogger', function () {
1818
before(async function () {
1919
tempFolder = await makeTemporaryToolkitFolder()
2020
const logPath = vscode.Uri.joinPath(vscode.Uri.file(tempFolder), 'log.txt')
21-
testLogger = makeLogger({ staticLogLevel: 'debug', logPaths: [logPath] })
21+
testLogger = makeLogger({ logLevel: 'debug', logPaths: [logPath] })
2222
})
2323

2424
after(async function () {

packages/core/src/test/techdebt.test.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import assert from 'assert'
77
import * as semver from 'semver'
88
import * as env from '../shared/vscode/env'
9-
import { defaultLogLevel } from '../shared/logger/activation'
10-
import packageJson from '../../package.json'
119

1210
// Checks project config and dependencies, to remind us to remove old things
1311
// when possible.
@@ -35,22 +33,4 @@ describe('tech debt', function () {
3533
'with node16+, we can now use AbortController to cancel Node things (child processes, HTTP requests, etc.)'
3634
)
3735
})
38-
39-
it('feature/standalone branch temporary debug log level for testing', async function () {
40-
if (!(process.env.GITHUB_BASE_REF ?? '').includes('master')) {
41-
this.skip()
42-
}
43-
44-
assert.strictEqual(
45-
defaultLogLevel,
46-
'info',
47-
'set loglevel defaults back to info for src/shared/logger/activation.ts. (revert this commit)'
48-
)
49-
50-
assert.strictEqual(
51-
packageJson.contributes.configuration.properties['aws.logLevel'].default,
52-
'info',
53-
'set loglevel defaults back to info for packages/amazonq/package.json, packages/toolkit/package.json. (revert this commit)'
54-
)
55-
})
5636
})

0 commit comments

Comments
 (0)