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
3296 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 { IDefaultLogLevelsService } from './defaultLogLevels.js';
20
import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
21
import { CounterSet } from '../../../../base/common/map.js';
22
import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js';
23
import { Schemas } from '../../../../base/common/network.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
return servicesAccessor.get(IInstantiationService).createInstance(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.TITLE.value).run();
36
}
37
});
38
39
registerAction2(class extends Action2 {
40
constructor() {
41
super({
42
id: 'workbench.action.setDefaultLogLevel',
43
title: nls.localize2('setDefaultLogLevel', "Set Default Log Level"),
44
category: Categories.Developer,
45
});
46
}
47
run(servicesAccessor: ServicesAccessor, logLevel: LogLevel, extensionId?: string): Promise<void> {
48
return servicesAccessor.get(IDefaultLogLevelsService).setDefaultLogLevel(logLevel, extensionId);
49
}
50
});
51
52
class LogOutputChannels extends Disposable implements IWorkbenchContribution {
53
54
private readonly contextKeys = new CounterSet<string>();
55
private readonly outputChannelRegistry = Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels);
56
57
constructor(
58
@ILoggerService private readonly loggerService: ILoggerService,
59
@IContextKeyService private readonly contextKeyService: IContextKeyService,
60
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
61
) {
62
super();
63
const contextKey = CONTEXT_LOG_LEVEL.bindTo(contextKeyService);
64
contextKey.set(LogLevelToString(loggerService.getLogLevel()));
65
this._register(loggerService.onDidChangeLogLevel(e => {
66
if (isLogLevel(e)) {
67
contextKey.set(LogLevelToString(loggerService.getLogLevel()));
68
}
69
}));
70
71
this.onDidAddLoggers(loggerService.getRegisteredLoggers());
72
this._register(loggerService.onDidChangeLoggers(({ added, removed }) => {
73
this.onDidAddLoggers(added);
74
this.onDidRemoveLoggers(removed);
75
}));
76
this._register(loggerService.onDidChangeVisibility(([resource, visibility]) => {
77
const logger = loggerService.getRegisteredLogger(resource);
78
if (logger) {
79
if (visibility) {
80
this.registerLogChannel(logger);
81
} else {
82
this.deregisterLogChannel(logger);
83
}
84
}
85
}));
86
this.registerShowWindowLogAction();
87
this._register(Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys))(() => this.onDidChangeContext()));
88
}
89
90
private onDidAddLoggers(loggers: Iterable<ILoggerResource>): void {
91
for (const logger of loggers) {
92
if (logger.when) {
93
const contextKeyExpr = ContextKeyExpr.deserialize(logger.when);
94
if (contextKeyExpr) {
95
for (const key of contextKeyExpr.keys()) {
96
this.contextKeys.add(key);
97
}
98
if (!this.contextKeyService.contextMatchesRules(contextKeyExpr)) {
99
continue;
100
}
101
}
102
}
103
if (logger.hidden) {
104
continue;
105
}
106
this.registerLogChannel(logger);
107
}
108
}
109
110
private onDidChangeContext(): void {
111
for (const logger of this.loggerService.getRegisteredLoggers()) {
112
if (logger.when) {
113
if (this.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(logger.when))) {
114
this.registerLogChannel(logger);
115
} else {
116
this.deregisterLogChannel(logger);
117
}
118
}
119
}
120
}
121
122
private onDidRemoveLoggers(loggers: Iterable<ILoggerResource>): void {
123
for (const logger of loggers) {
124
if (logger.when) {
125
const contextKeyExpr = ContextKeyExpr.deserialize(logger.when);
126
if (contextKeyExpr) {
127
for (const key of contextKeyExpr.keys()) {
128
this.contextKeys.delete(key);
129
}
130
}
131
}
132
this.deregisterLogChannel(logger);
133
}
134
}
135
136
private registerLogChannel(logger: ILoggerResource): void {
137
if (logger.group) {
138
this.registerCompoundLogChannel(logger.group.id, logger.group.name, logger);
139
return;
140
}
141
142
const channel = this.outputChannelRegistry.getChannel(logger.id);
143
if (channel && isSingleSourceOutputChannelDescriptor(channel) && this.uriIdentityService.extUri.isEqual(channel.source.resource, logger.resource)) {
144
return;
145
}
146
147
const existingChannel = this.outputChannelRegistry.getChannel(logger.id);
148
const remoteLogger = existingChannel && isSingleSourceOutputChannelDescriptor(existingChannel) && existingChannel.source.resource.scheme === Schemas.vscodeRemote ? this.loggerService.getRegisteredLogger(existingChannel.source.resource) : undefined;
149
if (remoteLogger) {
150
this.deregisterLogChannel(remoteLogger);
151
}
152
const hasToAppendRemote = existingChannel && logger.resource.scheme === Schemas.vscodeRemote;
153
const id = hasToAppendRemote ? `${logger.id}.remote` : logger.id;
154
const label = hasToAppendRemote ? nls.localize('remote name', "{0} (Remote)", logger.name ?? logger.id) : logger.name ?? logger.id;
155
this.outputChannelRegistry.registerChannel({ id, label, source: { resource: logger.resource }, log: true, extensionId: logger.extensionId });
156
}
157
158
private registerCompoundLogChannel(id: string, name: string, logger: ILoggerResource): void {
159
const channel = this.outputChannelRegistry.getChannel(id);
160
const source = { resource: logger.resource, name: logger.name ?? logger.id };
161
if (channel) {
162
if (isMultiSourceOutputChannelDescriptor(channel) && !channel.source.some(({ resource }) => this.uriIdentityService.extUri.isEqual(resource, logger.resource))) {
163
this.outputChannelRegistry.updateChannelSources(id, [...channel.source, source]);
164
}
165
} else {
166
this.outputChannelRegistry.registerChannel({ id, label: name, log: true, source: [source] });
167
}
168
}
169
170
private deregisterLogChannel(logger: ILoggerResource): void {
171
if (logger.group) {
172
const channel = this.outputChannelRegistry.getChannel(logger.group.id);
173
if (channel && isMultiSourceOutputChannelDescriptor(channel)) {
174
this.outputChannelRegistry.updateChannelSources(logger.group.id, channel.source.filter(({ resource }) => !this.uriIdentityService.extUri.isEqual(resource, logger.resource)));
175
}
176
} else {
177
this.outputChannelRegistry.removeChannel(logger.id);
178
}
179
}
180
181
private registerShowWindowLogAction(): void {
182
this._register(registerAction2(class ShowWindowLogAction extends Action2 {
183
constructor() {
184
super({
185
id: showWindowLogActionId,
186
title: nls.localize2('show window log', "Show Window Log"),
187
category: Categories.Developer,
188
f1: true
189
});
190
}
191
async run(servicesAccessor: ServicesAccessor): Promise<void> {
192
const outputService = servicesAccessor.get(IOutputService);
193
outputService.showChannel(windowLogId);
194
}
195
}));
196
}
197
}
198
199
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored);
200
201