Skip to content

Commit 0da7e92

Browse files
Merge pull request #4071 from PowerShell/andschwa/log-path
Use `context.storageUri` for logs and support `None` level
2 parents a128c36 + 8ff3703 commit 0da7e92

File tree

9 files changed

+64
-51
lines changed

9 files changed

+64
-51
lines changed

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -798,10 +798,11 @@
798798
"Verbose",
799799
"Normal",
800800
"Warning",
801-
"Error"
801+
"Error",
802+
"None"
802803
],
803804
"default": "Normal",
804-
"description": "Sets the logging verbosity level for the PowerShell Editor Services host executable. Valid values are 'Diagnostic', 'Verbose', 'Normal', 'Warning', and 'Error'"
805+
"description": "Sets the logging verbosity level for the PowerShell Editor Services host executable. Valid values are 'Diagnostic', 'Verbose', 'Normal', 'Warning', 'Error', and 'None'"
805806
},
806807
"powershell.developer.editorServicesWaitForDebugger": {
807808
"type": "boolean",

src/features/ExternalApi.ts

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export interface IPowerShellExtensionClient {
1919
unregisterExternalExtension(uuid: string): boolean;
2020
getPowerShellVersionDetails(uuid: string): Promise<IExternalPowerShellDetails>;
2121
waitUntilStarted(uuid: string): Promise<void>;
22+
getStorageUri(): vscode.Uri;
2223
}
2324

2425
/*
@@ -166,6 +167,10 @@ export class ExternalApiFeature extends LanguageClientConsumer implements IPower
166167
return this.sessionManager.waitUntilStarted();
167168
}
168169

170+
public getStorageUri(): vscode.Uri {
171+
return this.extensionContext.storageUri;
172+
}
173+
169174
public dispose() {
170175
// Nothing to dispose.
171176
}

src/logging.ts

+21-18
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export enum LogLevel {
1313
Normal,
1414
Warning,
1515
Error,
16+
None,
1617
}
1718

1819
/** Interface for logging operations. New features should use this interface for the "type" of logger.
@@ -29,19 +30,24 @@ export interface ILogger {
2930

3031
export class Logger implements ILogger {
3132

32-
public logBasePath: string;
33-
public logSessionPath: string;
33+
public logBasePath: vscode.Uri;
34+
public logSessionPath: vscode.Uri;
3435
public MinimumLogLevel: LogLevel = LogLevel.Normal;
3536

3637
private commands: vscode.Disposable[];
3738
private logChannel: vscode.OutputChannel;
38-
private logFilePath: string;
39+
private logFilePath: vscode.Uri;
3940

40-
constructor() {
41+
constructor(logBasePath: vscode.Uri) {
4142
this.logChannel = vscode.window.createOutputChannel("PowerShell Extension Logs");
4243

43-
this.logBasePath = path.resolve(__dirname, "../logs");
44-
utils.ensurePathExists(this.logBasePath);
44+
if (logBasePath === undefined) {
45+
// No workspace, we have to use another folder.
46+
this.logBasePath = vscode.Uri.file(path.resolve(__dirname, "../logs"));
47+
utils.ensurePathExists(this.logBasePath.fsPath);
48+
} else {
49+
this.logBasePath = vscode.Uri.joinPath(logBasePath, "logs");
50+
}
4551

4652
this.commands = [
4753
vscode.commands.registerCommand(
@@ -59,8 +65,8 @@ export class Logger implements ILogger {
5965
this.logChannel.dispose();
6066
}
6167

62-
public getLogFilePath(baseName: string): string {
63-
return path.resolve(this.logSessionPath, `${baseName}.log`);
68+
public getLogFilePath(baseName: string): vscode.Uri {
69+
return vscode.Uri.joinPath(this.logSessionPath, `${baseName}.log`);
6470
}
6571

6672
public writeAtLevel(logLevel: LogLevel, message: string, ...additionalMessages: string[]) {
@@ -136,17 +142,16 @@ export class Logger implements ILogger {
136142
}
137143
}
138144

139-
public startNewLog(minimumLogLevel: string = "Normal") {
145+
public async startNewLog(minimumLogLevel: string = "Normal") {
140146
this.MinimumLogLevel = this.logLevelNameToValue(minimumLogLevel.trim());
141147

142148
this.logSessionPath =
143-
path.resolve(
149+
vscode.Uri.joinPath(
144150
this.logBasePath,
145151
`${Math.floor(Date.now() / 1000)}-${vscode.env.sessionId}`);
146152

147153
this.logFilePath = this.getLogFilePath("vscode-powershell");
148-
149-
utils.ensurePathExists(this.logSessionPath);
154+
await vscode.workspace.fs.createDirectory(this.logSessionPath);
150155
}
151156

152157
private logLevelNameToValue(logLevelName: string): LogLevel {
@@ -156,6 +161,7 @@ export class Logger implements ILogger {
156161
case "normal": return LogLevel.Normal;
157162
case "warning": return LogLevel.Warning;
158163
case "error": return LogLevel.Error;
164+
case "none": return LogLevel.None;
159165
default: return LogLevel.Normal;
160166
}
161167
}
@@ -168,10 +174,7 @@ export class Logger implements ILogger {
168174
if (this.logSessionPath) {
169175
// Open the folder in VS Code since there isn't an easy way to
170176
// open the folder in the platform's file browser
171-
vscode.commands.executeCommand(
172-
"vscode.openFolder",
173-
vscode.Uri.file(this.logSessionPath),
174-
true);
177+
vscode.commands.executeCommand("vscode.openFolder", this.logSessionPath, true);
175178
}
176179
}
177180

@@ -181,9 +184,9 @@ export class Logger implements ILogger {
181184
`${now.toLocaleDateString()} ${now.toLocaleTimeString()} [${LogLevel[level].toUpperCase()}] - ${message}`;
182185

183186
this.logChannel.appendLine(timestampedMessage);
184-
if (this.logFilePath) {
187+
if (this.logFilePath && this.MinimumLogLevel !== LogLevel.None) {
185188
fs.appendFile(
186-
this.logFilePath,
189+
this.logFilePath.fsPath,
187190
timestampedMessage + os.EOL,
188191
(err) => {
189192
if (err) {

src/main.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IPower
125125
});
126126

127127
// Setup the logger.
128-
logger = new Logger();
128+
logger = new Logger(context.storageUri);
129129
logger.MinimumLogLevel = LogLevel[extensionSettings.developer.editorServicesLogLevel];
130130

131131
sessionManager =
@@ -180,6 +180,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IPower
180180
unregisterExternalExtension: uuid => externalApi.unregisterExternalExtension(uuid),
181181
getPowerShellVersionDetails: uuid => externalApi.getPowerShellVersionDetails(uuid),
182182
waitUntilStarted: uuid => externalApi.waitUntilStarted(uuid),
183+
getStorageUri: () => externalApi.getStorageUri(),
183184
};
184185
}
185186

src/process.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class PowerShellProcess {
5151
: "";
5252

5353
this.startPsesArgs +=
54-
`-LogPath '${PowerShellProcess.escapeSingleQuotes(editorServicesLogPath)}' ` +
54+
`-LogPath '${PowerShellProcess.escapeSingleQuotes(editorServicesLogPath.fsPath)}' ` +
5555
`-SessionDetailsPath '${PowerShellProcess.escapeSingleQuotes(this.sessionFilePath)}' ` +
5656
`-FeatureFlags @(${featureFlags}) `;
5757

src/session.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export class SessionManager implements Middleware {
111111
this.sessionSettings.powerShellDefaultVersion = exeNameOverride;
112112
}
113113

114-
this.log.startNewLog(this.sessionSettings.developer.editorServicesLogLevel);
114+
await this.log.startNewLog(this.sessionSettings.developer.editorServicesLogLevel);
115115

116116
// Create the PowerShell executable finder now
117117
this.powershellExeFinder = new PowerShellExeFinder(

test/core/paths.test.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@ import * as assert from "assert";
55
import * as fs from "fs";
66
import * as path from "path";
77
import * as vscode from "vscode";
8+
import { IPowerShellExtensionClient } from "../../src/features/ExternalApi";
89
import utils = require("../utils");
910

1011
describe("Path assumptions", function () {
11-
before(utils.ensureEditorServicesIsConnected);
12+
let storageUri: vscode.Uri;
13+
before(async () => {
14+
const extension: IPowerShellExtensionClient = await utils.ensureEditorServicesIsConnected();
15+
storageUri = extension.getStorageUri();
16+
});
1217

1318
// TODO: This is skipped because it interferes with other tests. Either
1419
// need to find a way to close the opened folder via a Code API, or find
@@ -22,6 +27,6 @@ describe("Path assumptions", function () {
2227
});
2328

2429
it("Creates the log folder at the correct path", function () {
25-
assert(fs.existsSync(path.resolve(utils.rootPath, "logs")));
30+
assert(fs.existsSync(vscode.Uri.joinPath(storageUri, "logs").fsPath));
2631
});
2732
});

test/features/ExternalApi.test.ts

+16-18
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,50 @@ import { IExternalPowerShellDetails, IPowerShellExtensionClient } from "../../sr
77

88
describe("ExternalApi feature", function () {
99
describe("External extension registration", function () {
10-
let powerShellExtensionClient: IPowerShellExtensionClient;
10+
let extension: IPowerShellExtensionClient;
1111
before(async function () {
12-
const powershellExtension = await utils.ensureExtensionIsActivated();
13-
powerShellExtensionClient = powershellExtension!.exports as IPowerShellExtensionClient;
12+
extension = await utils.ensureExtensionIsActivated();
1413
});
1514

1615
it("Registers and unregisters an extension", function () {
17-
const sessionId: string = powerShellExtensionClient.registerExternalExtension(utils.extensionId);
16+
const sessionId: string = extension.registerExternalExtension(utils.extensionId);
1817
assert.notStrictEqual(sessionId, "");
1918
assert.notStrictEqual(sessionId, null);
2019
assert.strictEqual(
21-
powerShellExtensionClient.unregisterExternalExtension(sessionId),
20+
extension.unregisterExternalExtension(sessionId),
2221
true);
2322
});
2423

2524
it("Registers and unregisters an extension with a version", function () {
26-
const sessionId: string = powerShellExtensionClient.registerExternalExtension(utils.extensionId, "v2");
25+
const sessionId: string = extension.registerExternalExtension(utils.extensionId, "v2");
2726
assert.notStrictEqual(sessionId, "");
2827
assert.notStrictEqual(sessionId, null);
2928
assert.strictEqual(
30-
powerShellExtensionClient.unregisterExternalExtension(sessionId),
29+
extension.unregisterExternalExtension(sessionId),
3130
true);
3231
});
3332

3433
it("Rejects if not registered", async function () {
3534
assert.rejects(
36-
async () => await powerShellExtensionClient.getPowerShellVersionDetails(""))
35+
async () => await extension.getPowerShellVersionDetails(""))
3736
});
3837

3938
it("Throws if attempting to register an extension more than once", async function () {
40-
const sessionId: string = powerShellExtensionClient.registerExternalExtension(utils.extensionId);
39+
const sessionId: string = extension.registerExternalExtension(utils.extensionId);
4140
try {
4241
assert.throws(
43-
() => powerShellExtensionClient.registerExternalExtension(utils.extensionId),
42+
() => extension.registerExternalExtension(utils.extensionId),
4443
{
4544
message: `The extension '${utils.extensionId}' is already registered.`
4645
});
4746
} finally {
48-
powerShellExtensionClient.unregisterExternalExtension(sessionId);
47+
extension.unregisterExternalExtension(sessionId);
4948
}
5049
});
5150

5251
it("Throws when unregistering an extension that isn't registered", async function () {
5352
assert.throws(
54-
() => powerShellExtensionClient.unregisterExternalExtension("not-real"),
53+
() => extension.unregisterExternalExtension("not-real"),
5554
{
5655
message: `No extension registered with session UUID: not-real`
5756
});
@@ -60,18 +59,17 @@ describe("ExternalApi feature", function () {
6059

6160
describe("PowerShell version details", () => {
6261
let sessionId: string;
63-
let powerShellExtensionClient: IPowerShellExtensionClient;
62+
let extension: IPowerShellExtensionClient;
6463

6564
before(async function () {
66-
const powershellExtension = await utils.ensureExtensionIsActivated();
67-
powerShellExtensionClient = powershellExtension!.exports as IPowerShellExtensionClient;
68-
sessionId = powerShellExtensionClient.registerExternalExtension(utils.extensionId);
65+
extension = await utils.ensureExtensionIsActivated();
66+
sessionId = extension.registerExternalExtension(utils.extensionId);
6967
});
7068

71-
after(function () { powerShellExtensionClient.unregisterExternalExtension(sessionId); });
69+
after(function () { extension.unregisterExternalExtension(sessionId); });
7270

7371
it("Gets non-empty version details from the PowerShell Editor Services", async function () {
74-
const versionDetails: IExternalPowerShellDetails = await powerShellExtensionClient.getPowerShellVersionDetails(sessionId);
72+
const versionDetails: IExternalPowerShellDetails = await extension.getPowerShellVersionDetails(sessionId);
7573

7674
assert.notStrictEqual(versionDetails.architecture, "");
7775
assert.notStrictEqual(versionDetails.architecture, null);

test/utils.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ export const rootPath = path.resolve(__dirname, "../../")
1414
const packageJSON: any = require(path.resolve(rootPath, "package.json"));
1515
export const extensionId = `${packageJSON.publisher}.${packageJSON.name}`;
1616

17-
export async function ensureExtensionIsActivated(): Promise<vscode.Extension<any>> {
17+
export async function ensureExtensionIsActivated(): Promise<IPowerShellExtensionClient> {
1818
const extension = vscode.extensions.getExtension(extensionId);
1919
if (!extension.isActive) { await extension.activate(); }
20-
return extension;
20+
return extension!.exports as IPowerShellExtensionClient;
2121
}
2222

23-
export async function ensureEditorServicesIsConnected(): Promise<void> {
24-
const powershellExtension = await ensureExtensionIsActivated();
25-
const client = powershellExtension!.exports as IPowerShellExtensionClient;
26-
const sessionId = client.registerExternalExtension(extensionId);
27-
await client.waitUntilStarted(sessionId);
28-
client.unregisterExternalExtension(sessionId);
23+
export async function ensureEditorServicesIsConnected(): Promise<IPowerShellExtensionClient> {
24+
const extension = await ensureExtensionIsActivated();
25+
const sessionId = extension.registerExternalExtension(extensionId);
26+
await extension.waitUntilStarted(sessionId);
27+
extension.unregisterExternalExtension(sessionId);
28+
return extension;
2929
}

0 commit comments

Comments
 (0)