Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd33d380

Browse files
committed
Refactor the logging and addcoder.httpClientLogLevel setting
1 parente97e687 commitd33d380

16 files changed

+385
-232
lines changed

‎package.json‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,23 @@
126126
"items": {
127127
"type":"string"
128128
}
129+
},
130+
"coder.httpClientLogLevel": {
131+
"markdownDescription":"Controls the verbosity of HTTP client logging. This affects what details are logged for each HTTP request and response.",
132+
"type":"string",
133+
"enum": [
134+
"none",
135+
"basic",
136+
"headers",
137+
"body"
138+
],
139+
"markdownEnumDescriptions": [
140+
"Disables all HTTP client logging",
141+
"Logs the request method, URL, length, and the response status code",
142+
"Logs everything from *basic* plus sanitized request and response headers",
143+
"Logs everything from *headers* plus request and response bodies (may include sensitive data)"
144+
],
145+
"default":"basic"
129146
}
130147
}
131148
},

‎src/agentMetadataHelper.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ export function createAgentMetadataWatcher(
6464

6565
socket.addEventListener("error",handleError);
6666

67+
socket.addEventListener("close",(event)=>{
68+
if(event.code!==1000){
69+
handleError(
70+
newError(
71+
`WebSocket closed unexpectedly:${event.code}${event.reason}`,
72+
),
73+
);
74+
}
75+
});
76+
6777
returnwatcher;
6878
}
6979

‎src/api/codeApi.ts‎

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,30 @@ import { type WorkspaceConfiguration } from "vscode";
1111
import{ClientOptions}from"ws";
1212
import{CertificateError}from"../error";
1313
import{getHeaderCommand,getHeaders}from"../headers";
14-
import{Logger}from"../logging/logger";
1514
import{
1615
createRequestMeta,
16+
logRequest,
1717
logRequestError,
18-
logRequestStart,
19-
logRequestSuccess,
20-
RequestConfigWithMeta,
21-
WsLogger,
22-
}from"../logging/netLog";
23-
import{OneWayCodeWebSocket}from"../websocket/oneWayCodeWebSocket";
18+
logResponse,
19+
}from"../logging/httpLogger";
20+
import{Logger}from"../logging/logger";
21+
import{RequestConfigWithMeta,HttpLogLevel}from"../logging/types";
22+
import{WsLogger}from"../logging/wsLogger";
23+
import{OneWayWebSocket}from"../websocket/oneWayWebSocket";
2424
import{createHttpAgent}from"./auth";
2525

2626
constcoderSessionTokenHeader="Coder-Session-Token";
2727

28+
typeWorkspaceConfigurationProvider=()=>WorkspaceConfiguration;
29+
2830
/**
2931
* Unified API class that includes both REST API methods from the base Api class
3032
* and WebSocket methods for real-time functionality.
3133
*/
3234
exportclassCodeApiextendsApi{
3335
privateconstructor(
3436
privatereadonlyoutput:Logger,
35-
privatereadonlycfg:WorkspaceConfiguration,
37+
privatereadonlyconfigProvider:WorkspaceConfigurationProvider,
3638
){
3739
super();
3840
}
@@ -45,15 +47,15 @@ export class CodeApi extends Api {
4547
baseUrl:string,
4648
token:string|undefined,
4749
output:Logger,
48-
cfg:WorkspaceConfiguration,
50+
configProvider:WorkspaceConfigurationProvider,
4951
):CodeApi{
50-
constclient=newCodeApi(output,cfg);
52+
constclient=newCodeApi(output,configProvider);
5153
client.setHost(baseUrl);
5254
if(token){
5355
client.setSessionToken(token);
5456
}
5557

56-
setupInterceptors(client,baseUrl,output,cfg);
58+
setupInterceptors(client,baseUrl,output,configProvider);
5759
returnclient;
5860
}
5961

@@ -120,8 +122,8 @@ export class CodeApi extends Api {
120122
coderSessionTokenHeader
121123
]asstring|undefined;
122124

123-
consthttpAgent=createHttpAgent(this.cfg);
124-
constwebSocket=newOneWayCodeWebSocket<TData>({
125+
consthttpAgent=createHttpAgent(this.configProvider());
126+
constwebSocket=newOneWayWebSocket<TData>({
125127
location:baseUrl,
126128
...configs,
127129
options:{
@@ -167,12 +169,16 @@ function setupInterceptors(
167169
client:CodeApi,
168170
baseUrl:string,
169171
output:Logger,
170-
cfg:WorkspaceConfiguration,
172+
configProvider:WorkspaceConfigurationProvider,
171173
):void{
172-
addLoggingInterceptors(client.getAxiosInstance(),output);
174+
addLoggingInterceptors(client.getAxiosInstance(),output,configProvider);
173175

174176
client.getAxiosInstance().interceptors.request.use(async(config)=>{
175-
constheaders=awaitgetHeaders(baseUrl,getHeaderCommand(cfg),output);
177+
constheaders=awaitgetHeaders(
178+
baseUrl,
179+
getHeaderCommand(configProvider()),
180+
output,
181+
);
176182
// Add headers from the header command.
177183
Object.entries(headers).forEach(([key,value])=>{
178184
config.headers[key]=value;
@@ -181,7 +187,7 @@ function setupInterceptors(
181187
// Configure proxy and TLS.
182188
// Note that by default VS Code overrides the agent. To prevent this, set
183189
// `http.proxySupport` to `on` or `off`.
184-
constagent=createHttpAgent(cfg);
190+
constagent=createHttpAgent(configProvider());
185191
config.httpsAgent=agent;
186192
config.httpAgent=agent;
187193
config.proxy=false;
@@ -198,12 +204,16 @@ function setupInterceptors(
198204
);
199205
}
200206

201-
functionaddLoggingInterceptors(client:AxiosInstance,logger:Logger){
207+
functionaddLoggingInterceptors(
208+
client:AxiosInstance,
209+
logger:Logger,
210+
configProvider:WorkspaceConfigurationProvider,
211+
){
202212
client.interceptors.request.use(
203213
(config)=>{
204214
constmeta=createRequestMeta();
205215
(configasRequestConfigWithMeta).metadata=meta;
206-
logRequestStart(logger,meta.requestId,config);
216+
logRequest(logger,meta.requestId,config,getLogLevel(configProvider()));
207217
returnconfig;
208218
},
209219
(error:unknown)=>{
@@ -216,7 +226,7 @@ function addLoggingInterceptors(client: AxiosInstance, logger: Logger) {
216226
(response)=>{
217227
constmeta=(response.configasRequestConfigWithMeta).metadata;
218228
if(meta){
219-
logRequestSuccess(logger,meta,response);
229+
logResponse(logger,meta,response,getLogLevel(configProvider()));
220230
}
221231
returnresponse;
222232
},
@@ -226,3 +236,10 @@ function addLoggingInterceptors(client: AxiosInstance, logger: Logger) {
226236
},
227237
);
228238
}
239+
240+
functiongetLogLevel(cfg:WorkspaceConfiguration):HttpLogLevel{
241+
constlogLevelStr=cfg
242+
.get("coder.httpClientLogLevel",HttpLogLevel[HttpLogLevel.BASIC])
243+
.toUpperCase();
244+
returnHttpLogLevel[logLevelStraskeyoftypeofHttpLogLevel];
245+
}

‎src/api/workspace.ts‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,6 @@ export async function waitForBuild(
9696
logs,
9797
);
9898

99-
constcloseHandler=()=>{
100-
resolve();
101-
};
102-
10399
socket.addEventListener("message",(data)=>{
104100
if(data.parseError){
105101
writeEmitter.fire(
@@ -111,10 +107,6 @@ export async function waitForBuild(
111107
});
112108

113109
socket.addEventListener("error",(error)=>{
114-
// Do not want to trigger the close handler and resolve the promise normally.
115-
socket.removeEventListener("close",closeHandler);
116-
socket.close();
117-
118110
constbaseUrlRaw=client.getAxiosInstance().defaults.baseURL;
119111
returnreject(
120112
newError(
@@ -123,7 +115,7 @@ export async function waitForBuild(
123115
);
124116
});
125117

126-
socket.addEventListener("close",closeHandler);
118+
socket.addEventListener("close",()=>resolve());
127119
});
128120

129121
writeEmitter.fire("Build complete\r\n");

‎src/commands.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,10 @@ export class Commands {
240240
token:string,
241241
isAutologin:boolean,
242242
):Promise<{user:User;token:string}|null>{
243-
constcfg=vscode.workspace.getConfiguration();
244-
constclient=CodeApi.create(url,token,this.storage.output,cfg);
245-
if(!needToken(cfg)){
243+
constclient=CodeApi.create(url,token,this.storage.output,()=>
244+
vscode.workspace.getConfiguration(),
245+
);
246+
if(!needToken(vscode.workspace.getConfiguration())){
246247
try{
247248
constuser=awaitclient.getAuthenticatedUser();
248249
// For non-token auth, we write a blank token since the `vscodessh`

‎src/extension.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
6666
url||"",
6767
awaitstorage.getSessionToken(),
6868
storage.output,
69-
vscode.workspace.getConfiguration(),
69+
()=>vscode.workspace.getConfiguration(),
7070
);
7171

7272
constmyWorkspacesProvider=newWorkspaceProvider(

‎src/inbox.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
import*asvscodefrom"vscode";
66
import{CodeApi}from"./api/codeApi";
77
import{typeStorage}from"./storage";
8-
import{OneWayCodeWebSocket}from"./websocket/oneWayCodeWebSocket";
8+
import{OneWayWebSocket}from"./websocket/oneWayWebSocket";
99

1010
// These are the template IDs of our notifications.
1111
// Maybe in the future we should avoid hardcoding
@@ -16,7 +16,7 @@ const TEMPLATE_WORKSPACE_OUT_OF_DISK = "f047f6a3-5713-40f7-85aa-0394cce9fa3a";
1616
exportclassInboximplementsvscode.Disposable{
1717
readonly #storage:Storage;
1818
#disposed=false;
19-
#socket:OneWayCodeWebSocket<GetInboxNotificationResponse>;
19+
#socket:OneWayWebSocket<GetInboxNotificationResponse>;
2020

2121
constructor(workspace:Workspace,client:CodeApi,storage:Storage){
2222
this.#storage=storage;

‎src/logging/formatters.ts‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
importtype{InternalAxiosRequestConfig}from"axios";
2+
importprettyBytesfrom"pretty-bytes";
3+
4+
constSENSITIVE_HEADERS=["Coder-Session-Token","Proxy-Authorization"];
5+
6+
exportfunctionformatMethod(method:string|undefined):string{
7+
return(method??"GET").toUpperCase();
8+
}
9+
10+
exportfunctionformatContentLength(headers:Record<string,unknown>):string{
11+
constlen=headers["content-length"];
12+
if(len&&typeoflen==="string"){
13+
constbytes=parseInt(len,10);
14+
returnisNaN(bytes) ?"(?b)" :`(${prettyBytes(bytes)})`;
15+
}
16+
return"(?b)";
17+
}
18+
19+
exportfunctionformatUri(
20+
config:InternalAxiosRequestConfig|undefined,
21+
):string{
22+
returnconfig?.url||"<no url>";
23+
}
24+
25+
exportfunctionformatHeaders(headers:Record<string,unknown>):string{
26+
constformattedHeaders=Object.entries(headers)
27+
.map(([key,value])=>{
28+
if(SENSITIVE_HEADERS.includes(key)){
29+
return`${key}: <redacted>`;
30+
}
31+
return`${key}:${value}`;
32+
})
33+
.join("\n")
34+
.trim();
35+
36+
returnformattedHeaders.length>0 ?formattedHeaders :"<no headers>";
37+
}
38+
39+
exportfunctionformatBody(body:unknown):string{
40+
if(body){
41+
returnJSON.stringify(body);
42+
}else{
43+
return"<no body>";
44+
}
45+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp