Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/logs/common/logs.contribution.ts
5284 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as nls from '../../../../nls.js';
7
import { Registry } from '../../../../platform/registry/common/platform.js';
8
import { Categories } from '../../../../platform/action/common/actionCommonCategories.js';
9
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
10
import { SetLogLevelAction } from './logsActions.js';
11
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from '../../../common/contributions.js';
12
import { IOutputChannelRegistry, IOutputService, Extensions, isMultiSourceOutputChannelDescriptor, isSingleSourceOutputChannelDescriptor } from '../../../services/output/common/output.js';
13
import { Disposable } from '../../../../base/common/lifecycle.js';
14
import { CONTEXT_LOG_LEVEL, ILoggerResource, ILoggerService, LogLevel, LogLevelToString, isLogLevel } from '../../../../platform/log/common/log.js';
15
import { LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js';
16
import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
17
import { Event } from '../../../../base/common/event.js';
18
import { windowLogId, showWindowLogActionId } from '../../../services/log/common/logConstants.js';
19
import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
20
import { CounterSet } from '../../../../base/common/map.js';
21
import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';
22
import { Schemas } from '../../../../base/common/network.js';
23
import { IDefaultLogLevelsService } from '../../../services/log/common/defaultLogLevels.js';
24
25
registerAction2(class extends Action2 {
26
constructor() {
27
super({
28
id: SetLogLevelAction.ID,
29
title: SetLogLevelAction.TITLE,
30
category: Categories.Developer,
31
f1: true
32
});
33
}
34
run(servicesAccessor: ServicesAccessor): Promise<void> {
35
const action = servicesAccessor.get(IInstantiationService).createInstance(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.TITLE.value);
36
return action.run().finally(() => action.dispose());
37
}
38
});
39
40
registerAction2(class extends Action2 {
41
constructor() {
42
super({
43
id: 'workbench.action.setDefaultLogLevel',
44
title: nls.localize2('setDefaultLogLevel', "Set Default Log Level"),
45
category: Categories.Developer,
46
});
47
}
48
run(servicesAccessor: ServicesAccessor, logLevel: LogLevel, extensionId?: string): Promise<void> {
49
return servicesAccessor.get(IDefaultLogLevelsService).setDefaultLogLevel(logLevel, extensionId);
50
}
51
});
52
53
class LogOutputChannels extends Disposable implements IWorkbenchContribution {
54
55
private readonly contextKeys = new CounterSet<string>();
56
private readonly outputChannelRegistry = Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels);
57
58
constructor(
59
@ILoggerService private readonly loggerService: ILoggerService,
60
@IContextKeyService private readonly contextKeyService: IContextKeyService,
61
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
62
) {
63
super();
64
const contextKey = CONTEXT_LOG_LEVEL.bindTo(contextKeyService);
65
contextKey.set(LogLevelToString(loggerService.getLogLevel()));
66
this._register(loggerService.onDidChangeLogLevel(e => {
67
if (isLogLevel(e)) {
68
contextKey.set(LogLevelToString(loggerService.getLogLevel()));
69
}
70
}));
71
72
this.onDidAddLoggers(loggerService.getRegisteredLoggers());
73
this._register(loggerService.onDidChangeLoggers(({ added, removed }) => {
74
this.onDidAddLoggers(added);
75
this.onDidRemoveLoggers(removed);
76
}));
77
this._register(loggerService.onDidChangeVisibility(([resource, visibility]) => {
78
const logger = loggerService.getRegisteredLogger(resource);
79
if (logger) {
80
if (visibility) {
81
this.registerLogChannel(logger);
82
} else {
83
this.deregisterLogChannel(logger);
84
}
85
}
86
}));
87
this.registerShowWindowLogAction();
88
this._register(Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys))(() => this.onDidChangeContext()));
89
}
90
91
private onDidAddLoggers(loggers: Iterable<ILoggerResource>): void {
92
for (const logger of loggers) {
93
if (logger.when) {
94
const contextKeyExpr = ContextKeyExpr.deserialize(logger.when);
95
if (contextKeyExpr) {
96
for (const key of contextKeyExpr.keys()) {
97
this.contextKeys.add(key);
98
}
99
if (!this.contextKeyService.contextMatchesRules(contextKeyExpr)) {
100
continue;
101
}
102
}
103
}
104
if (logger.hidden) {
105
continue;
106
}
107
this.registerLogChannel(logger);
108
}
109
}
110
111
private onDidChangeContext(): void {
112
for (const logger of this.loggerService.getRegisteredLoggers()) {
113
if (logger.when) {
114
if (this.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(logger.when))) {
115
this.registerLogChannel(logger);
116
} else {
117
this.deregisterLogChannel(logger);
118
}
119
}
120
}
121
}
122
123
private onDidRemoveLoggers(loggers: Iterable<ILoggerResource>): void {
124
for (const logger of loggers) {
125
if (logger.when) {
126
const contextKeyExpr = ContextKeyExpr.deserialize(logger.when);
127
if (contextKeyExpr) {
128
for (const key of contextKeyExpr.keys()) {
129
this.contextKeys.delete(key);
130
}
131
}
132
}
133
this.deregisterLogChannel(logger);
134
}
135
}
136
137
private registerLogChannel(logger: ILoggerResource): void {
138
if (logger.group) {
139
this.registerCompoundLogChannel(logger.group.id, logger.group.name, logger);
140
return;
141
}
142
143
const channel = this.outputChannelRegistry.getChannel(logger.id);
144
if (channel && isSingleSourceOutputChannelDescriptor(channel) && this.uriIdentityService.extUri.isEqual(channel.source.resource, logger.resource)) {
145
return;
146
}
147
148
const existingChannel = this.outputChannelRegistry.getChannel(logger.id);
149
const remoteLogger = existingChannel && isSingleSourceOutputChannelDescriptor(existingChannel) && existingChannel.source.resource.scheme === Schemas.vscodeRemote ? this.loggerService.getRegisteredLogger(existingChannel.source.resource) : undefined;
150
if (remoteLogger) {
151
this.deregisterLogChannel(remoteLogger);
152
}
153
const hasToAppendRemote = existingChannel && logger.resource.scheme === Schemas.vscodeRemote;
154
const id = hasToAppendRemote ? `${logger.id}.remote` : logger.id;
155
const label = hasToAppendRemote ? nls.localize('remote name', "{0} (Remote)", logger.name ?? logger.id) : logger.name ?? logger.id;
156
this.outputChannelRegistry.registerChannel({ id, label, source: { resource: logger.resource }, log: true, extensionId: logger.extensionId });
157
}
158
159
private registerCompoundLogChannel(id: string, name: string, logger: ILoggerResource): void {
160
const channel = this.outputChannelRegistry.getChannel(id);
161
const source = { resource: logger.resource, name: logger.name ?? logger.id };
162
if (channel) {
163
if (isMultiSourceOutputChannelDescriptor(channel) && !channel.source.some(({ resource }) => this.uriIdentityService.extUri.isEqual(resource, logger.resource))) {
164
this.outputChannelRegistry.updateChannelSources(id, [...channel.source, source]);
165
}
166
} else {
167
this.outputChannelRegistry.registerChannel({ id, label: name, log: true, source: [source] });
168
}
169
}
170
171
private deregisterLogChannel(logger: ILoggerResource): void {
172
if (logger.group) {
173
const channel = this.outputChannelRegistry.getChannel(logger.group.id);
174
if (channel && isMultiSourceOutputChannelDescriptor(channel)) {
175
this.outputChannelRegistry.updateChannelSources(logger.group.id, channel.source.filter(({ resource }) => !this.uriIdentityService.extUri.isEqual(resource, logger.resource)));
176
}
177
} else {
178
this.outputChannelRegistry.removeChannel(logger.id);
179
}
180
}
181
182
private registerShowWindowLogAction(): void {
183
this._register(registerAction2(class ShowWindowLogAction extends Action2 {
184
constructor() {
185
super({
186
id: showWindowLogActionId,
187
title: nls.localize2('show window log', "Show Window Log"),
188
category: Categories.Developer,
189
f1: true
190
});
191
}
192
async run(servicesAccessor: ServicesAccessor): Promise<void> {
193
const outputService = servicesAccessor.get(IOutputService);
194
outputService.showChannel(windowLogId);
195
}
196
}));
197
}
198
}
199
200
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored);
201
202