Skip to content

Commit

Permalink
feat(logging): leverage vscode OutputChannel, drop watch/cleanup #4688
Browse files Browse the repository at this point in the history
Problem:
- We start a logfile watcher on startup, which adds (1) unnecessary
  latency and complexity, and (2) uses node fs watcher (unreliable, not
  web-compatible) instead of vscode watcher.
- vscode OutputChannel has gained capabilities such that we no longer
  need to manage logfiles:
    - "Open Output in Editor"
    - Log syntax highlighting
    - Set log level (TODO: we aren't currently leveraging this)

Solution:
- Only log to OutputChannel. Don't log to a file unless
  "aws.dev.logfile" (developer-mode setting) is set.
- Update "View Logs" commands to show the "AWS Toolkit Logs"
  OutputChannel instead of the logfile (unless "aws.dev.logfile" is
  set).
- Remove all logfile watch/cleanup code.
  • Loading branch information
justinmk3 authored Apr 11, 2024
1 parent 7d7d9bb commit 3d4c65e
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 235 deletions.
83 changes: 3 additions & 80 deletions packages/core/src/shared/logger/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,17 @@
* SPDX-License-Identifier: Apache-2.0
*/

import * as path from 'path'
import * as vscode from 'vscode'
import * as nls from 'vscode-nls'
import { Logger, LogLevel, getLogger } from '.'
import { setLogger } from './logger'
import { logOutputChannel } from './outputChannel'
import { WinstonToolkitLogger } from './winstonToolkitLogger'
import { waitUntil } from '../utilities/timeoutUtils'
import { cleanLogFiles } from './util'
import { Settings } from '../settings'
import { Logging } from './commands'
import { resolvePath } from '../utilities/pathUtils'
import { isWeb } from '../../common/webUtils'
import { fsCommon } from '../../srcShared/fs'

const localize = nls.loadMessageBundle()

const defaultLogLevel: LogLevel = 'info'

/**
Expand All @@ -32,15 +26,13 @@ export async function activate(
const chan = logOutputChannel
const settings = Settings.instance.getSection('aws')
const devLogfile = settings.get('dev.logfile', '')
const logUri = devLogfile
? vscode.Uri.file(resolvePath(devLogfile))
: vscode.Uri.joinPath(extensionContext.logUri, makeLogFilename())
const logUri = devLogfile ? vscode.Uri.file(resolvePath(devLogfile)) : undefined

await fsCommon.mkdir(extensionContext.logUri)

const mainLogger = makeLogger(
{
logPaths: [logUri],
logPaths: logUri ? [logUri] : undefined,
outputChannels: [chan],
useConsoleLog: isWeb(),
},
Expand All @@ -54,7 +46,7 @@ export async function activate(
setLogger(
makeLogger(
{
logPaths: [logUri],
logPaths: logUri ? [logUri] : undefined,
outputChannels: [outputChannel, chan],
},
extensionContext.subscriptions
Expand All @@ -79,18 +71,6 @@ export async function activate(

const commands = new Logging(logUri, mainLogger)
extensionContext.subscriptions.push(...Object.values(Logging.declared).map(c => c.register(commands)))

createLogWatcher(logUri)
.then(sub => {
extensionContext.subscriptions.push(sub)
})
.catch(err => {
getLogger().warn('Failed to start log file watcher: %s', err)
})

cleanLogFiles(path.dirname(logUri.fsPath)).catch(err => {
getLogger().warn('Failed to clean-up old logs: %s', err)
})
}

/**
Expand Down Expand Up @@ -149,60 +129,3 @@ function getLogLevel(): LogLevel {
const configuration = Settings.instance.getSection('aws')
return configuration.get('logLevel', defaultLogLevel)
}

/**
* Creates a name for the toolkit's logfile.
* Essentially an ISO string, but in the local timezone and without the trailing "Z"
* @returns Log filename
*/
function makeLogFilename(): string {
const now = new Date()
// local to machine: use getMonth/Date instead of UTC equivalent
// month is zero-terminated: offset by 1
const m = (now.getMonth() + 1).toString().padStart(2, '0')
const d = now.getDate().toString().padStart(2, '0')
const h = now.getHours().toString().padStart(2, '0')
const mn = now.getMinutes().toString().padStart(2, '0')
const s = now.getSeconds().toString().padStart(2, '0')
const dt = `${now.getFullYear()}${m}${d}T${h}${mn}${s}`

return `aws_toolkit_${dt}.log`
}

/**
* Watches for renames on the log file and notifies the user.
*/
async function createLogWatcher(logFile: vscode.Uri): Promise<vscode.Disposable> {
if (isWeb()) {
getLogger().debug(`Not watching log file since we are in Browser.`)
return { dispose: () => {} }
}

const exists = await waitUntil(() => fsCommon.existsFile(logFile), { interval: 1000, timeout: 60000 })

if (!exists) {
getLogger().warn(`Log file ${logFile.path} does not exist!`)
return { dispose: () => {} }
}

let checking = false
// TODO: fs.watch() has many problems, consider instead:
// - https://github.com/paulmillr/chokidar
// - https://www.npmjs.com/package/fb-watchman
const fs = await import('fs')
const watcher = fs.watch(logFile.fsPath, async eventType => {
if (checking || eventType !== 'rename') {
return
}
checking = true
if (!(await fsCommon.existsFile(logFile))) {
await vscode.window.showWarningMessage(
localize('AWS.log.logFileMove', 'The log file for this session has been moved or deleted.')
)
watcher.close()
}
checking = false
})

return { dispose: () => watcher.close() }
}
14 changes: 12 additions & 2 deletions packages/core/src/shared/logger/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import * as vscode from 'vscode'
import { Logger } from '.'
import { Logger, showLogOutputChannel } from '.'
import { telemetry } from '../telemetry/telemetry'
import { Commands } from '../vscode/commands2'
import { getLogger } from './logger'
Expand All @@ -25,18 +25,28 @@ function clearSelection(editor: vscode.TextEditor): void {

export class Logging {
public static readonly declared = {
// Calls openLogUri().
viewLogs: Commands.from(this).declareOpenLogUri('aws.viewLogs'),
// Calls openLogId().
viewLogsAtMessage: Commands.from(this).declareOpenLogId('aws.viewLogsAtMessage'),
}

public constructor(private readonly logUri: vscode.Uri, private readonly logger: Logger) {}
public constructor(private readonly logUri: vscode.Uri | undefined, private readonly logger: Logger) {}

public async openLogUri(): Promise<vscode.TextEditor | undefined> {
if (!this.logUri) {
showLogOutputChannel()
return undefined
}
telemetry.toolkit_viewLogs.emit({ result: 'Succeeded' })
return vscode.window.showTextDocument(this.logUri)
}

public async openLogId(logId: number) {
if (!this.logUri) {
showLogOutputChannel()
return
}
const msg = this.logger.getLogById(logId, this.logUri)
const editor = await this.openLogUri()
if (!msg || !editor) {
Expand Down
80 changes: 0 additions & 80 deletions packages/core/src/shared/logger/util.ts

This file was deleted.

73 changes: 0 additions & 73 deletions packages/core/src/test/shared/logger/util.test.ts

This file was deleted.

0 comments on commit 3d4c65e

Please sign in to comment.