Skip to content

Commit 0600749

Browse files
authored
feat: Use native LSP logger (#3148)
1 parent 083ca10 commit 0600749

14 files changed

+47
-196
lines changed

.changeset/stale-experts-explode.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"graphql-language-service-cli": patch
3+
"graphql-language-service-server": minor
4+
"graphql-language-service": patch
5+
---
6+
7+
Use native LSP logger instead of manual file based logging. This fixes errors in Neovim when using the GraphQL LSP.

packages/graphql-language-service-cli/src/cli.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import yargs from 'yargs';
1111
import client from './client';
1212

13-
import { Logger, startServer } from 'graphql-language-service-server';
13+
import { startServer } from 'graphql-language-service-server';
1414

1515
const { argv } = yargs
1616
.usage(
@@ -128,8 +128,9 @@ if (command === 'server') {
128128
}
129129
// eslint-disable-next-line promise/prefer-await-to-then -- don't know if I can use top level await here
130130
startServer(options).catch(error => {
131-
const logger = new Logger();
132-
logger.error(String(error));
131+
process.stderr.write(
132+
'An error was thrown from GraphQL language service: ' + String(error),
133+
);
133134
});
134135
} else {
135136
client(command as string, argv as Record<string, string>);

packages/graphql-language-service-server/src/GraphQLCache.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import type {
2222
ObjectTypeInfo,
2323
Uri,
2424
} from 'graphql-language-service';
25+
import type { Logger } from 'vscode-languageserver';
2526

2627
import * as fs from 'node:fs';
2728
import { readFile } from 'node:fs/promises';
@@ -41,7 +42,6 @@ import stringToHash from './stringToHash';
4142
import glob from 'glob';
4243
import { LoadConfigOptions } from './types';
4344
import { URI } from 'vscode-uri';
44-
import { Logger } from './Logger';
4545

4646
// Maximum files to read when processing GraphQL files.
4747
const MAX_READS = 200;

packages/graphql-language-service-server/src/GraphQLLanguageService.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,13 @@ import {
4949

5050
import { GraphQLConfig, GraphQLProjectConfig } from 'graphql-config';
5151

52+
import type { Logger } from 'vscode-languageserver';
5253
import {
5354
Hover,
5455
SymbolInformation,
5556
SymbolKind,
5657
} from 'vscode-languageserver-types';
5758

58-
import { Logger } from './Logger';
59-
6059
const KIND_TO_SYMBOL_KIND: { [key: string]: SymbolKind } = {
6160
[Kind.FIELD]: SymbolKind.Field,
6261
[Kind.OPERATION_DEFINITION]: SymbolKind.Class,

packages/graphql-language-service-server/src/Logger.ts

+11-74
Original file line numberDiff line numberDiff line change
@@ -8,94 +8,31 @@
88
*/
99

1010
import { Logger as VSCodeLogger } from 'vscode-jsonrpc';
11-
import { DiagnosticSeverity } from 'vscode-languageserver';
12-
13-
import * as fs from 'node:fs';
14-
import * as os from 'node:os';
15-
import { join } from 'node:path';
16-
import { Socket } from 'node:net';
17-
18-
import {
19-
DIAGNOSTIC_SEVERITY,
20-
SeverityEnum,
21-
SEVERITY,
22-
} from 'graphql-language-service';
11+
import { Connection } from 'vscode-languageserver';
2312

2413
export class Logger implements VSCodeLogger {
25-
_logFilePath: string;
26-
_stderrOnly: boolean;
27-
28-
constructor(tmpDir?: string, stderrOnly?: boolean) {
29-
const dir = join(tmpDir || os.tmpdir(), 'graphql-language-service-logs');
30-
try {
31-
if (!fs.existsSync(dir)) {
32-
fs.mkdirSync(dir);
33-
}
34-
} catch {
35-
// intentionally no-op. Don't block the language server even if
36-
// the necessary setup cannot be completed for logger.
37-
}
38-
39-
this._logFilePath = join(
40-
dir,
41-
`graphql-language-service-log-${
42-
os.userInfo().username
43-
}-${getDateString()}.log`,
44-
);
45-
46-
this._stderrOnly = stderrOnly || false;
47-
}
14+
constructor(private _connection: Connection) {}
4815

4916
error(message: string): void {
50-
this._log(message, SEVERITY.Error);
17+
this._connection.console.error(message);
5118
}
5219

5320
warn(message: string): void {
54-
this._log(message, SEVERITY.Warning);
21+
this._connection.console.warn(message);
5522
}
5623

5724
info(message: string): void {
58-
this._log(message, SEVERITY.Information);
25+
this._connection.console.info(message);
5926
}
6027

6128
log(message: string): void {
62-
this._log(message, SEVERITY.Hint);
63-
}
64-
65-
_log(message: string, severityKey: SeverityEnum): void {
66-
const timestamp = new Date().toLocaleString();
67-
const severity = DIAGNOSTIC_SEVERITY[severityKey];
68-
const { pid } = process;
69-
70-
const stringMessage = String(message).trim();
71-
const logMessage = `${timestamp} [${severity}] (pid: ${pid}) graphql-language-service-usage-logs: ${stringMessage}\n`;
72-
// write to the file in tmpdir
73-
fs.appendFile(this._logFilePath, logMessage, _error => {});
74-
// @TODO: enable with debugging
75-
if (severityKey !== SEVERITY.Hint) {
76-
this._getOutputStream(severity).write(logMessage, err => {
77-
if (err) {
78-
// eslint-disable-next-line no-console
79-
console.error(err);
80-
}
81-
});
82-
}
83-
}
84-
85-
_getOutputStream(severity: DiagnosticSeverity): Socket {
86-
if (this._stderrOnly || severity === DIAGNOSTIC_SEVERITY.Error) {
87-
return process.stderr;
88-
}
89-
90-
return process.stdout;
29+
this._connection.console.log(message);
9130
}
9231
}
9332

94-
// function getUnixTime() {
95-
// return new Date().getTime() / 1000;
96-
// }
97-
98-
function getDateString() {
99-
const date = new Date();
100-
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
33+
export class NoopLogger implements VSCodeLogger {
34+
error() {}
35+
warn() {}
36+
info() {}
37+
log() {}
10138
}

packages/graphql-language-service-server/src/MessageProcessor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ import type {
5353
WorkspaceSymbolParams,
5454
Connection,
5555
DidChangeConfigurationRegistrationOptions,
56+
Logger,
5657
} from 'vscode-languageserver/node';
5758

5859
import type { UnnormalizedTypeDefPointer } from '@graphql-tools/load';
5960

6061
import { getGraphQLCache, GraphQLCache } from './GraphQLCache';
6162
import { parseDocument, DEFAULT_SUPPORTED_EXTENSIONS } from './parseDocument';
6263

63-
import { Logger } from './Logger';
6464
import { printSchema, visit, parse, FragmentDefinitionNode } from 'graphql';
6565
import { tmpdir } from 'node:os';
6666
import {

packages/graphql-language-service-server/src/__tests__/GraphQLLanguageService-test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { GraphQLConfig } from 'graphql-config';
1313
import { GraphQLLanguageService } from '../GraphQLLanguageService';
1414
import { SymbolKind } from 'vscode-languageserver-protocol';
1515
import { Position } from 'graphql-language-service';
16-
import { Logger } from '../Logger';
16+
import { NoopLogger } from '../Logger';
1717

1818
const MOCK_CONFIG = {
1919
filepath: join(__dirname, '.graphqlrc.yml'),
@@ -122,7 +122,7 @@ describe('GraphQLLanguageService', () => {
122122
beforeEach(() => {
123123
languageService = new GraphQLLanguageService(
124124
mockCache as any,
125-
new Logger(),
125+
new NoopLogger(),
126126
);
127127
});
128128

packages/graphql-language-service-server/src/__tests__/Logger-test.ts

-64
This file was deleted.

packages/graphql-language-service-server/src/__tests__/MessageProcessor-test.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* LICENSE file in the root directory of this source tree.
77
*
88
*/
9-
import { tmpdir } from 'node:os';
109
import { SymbolKind } from 'vscode-languageserver';
1110
import { FileChangeType } from 'vscode-languageserver-protocol';
1211
import { Position, Range } from 'graphql-language-service';
@@ -22,7 +21,7 @@ import { loadConfig } from 'graphql-config';
2221

2322
import type { DefinitionQueryResult, Outline } from 'graphql-language-service';
2423

25-
import { Logger } from '../Logger';
24+
import { NoopLogger } from '../Logger';
2625
import { pathToFileURL } from 'node:url';
2726

2827
jest.mock('node:fs', () => ({
@@ -31,7 +30,7 @@ jest.mock('node:fs', () => ({
3130
}));
3231

3332
describe('MessageProcessor', () => {
34-
const logger = new Logger(tmpdir());
33+
const logger = new NoopLogger();
3534
const messageProcessor = new MessageProcessor({
3635
// @ts-ignore
3736
connection: {},

packages/graphql-language-service-server/src/__tests__/findGraphQLTags-test.ts

+5-21
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
* LICENSE file in the root directory of this source tree.
77
*
88
*/
9-
import { tmpdir } from 'node:os';
109

1110
import { findGraphQLTags as baseFindGraphQLTags } from '../findGraphQLTags';
1211

1312
jest.mock('../Logger');
1413

15-
import { Logger } from '../Logger';
14+
import { NoopLogger } from '../Logger';
1615

1716
describe('findGraphQLTags', () => {
18-
const logger = new Logger(tmpdir());
17+
const logger = new NoopLogger();
1918
const findGraphQLTags = (text: string, ext: string) =>
2019
baseFindGraphQLTags(text, ext, '', logger);
2120

@@ -296,12 +295,7 @@ query {id}`);
296295
.spyOn(process.stderr, 'write')
297296
.mockImplementation(() => true);
298297

299-
const contents = baseFindGraphQLTags(
300-
text,
301-
'.svelte',
302-
'',
303-
new Logger(tmpdir(), false),
304-
);
298+
const contents = baseFindGraphQLTags(text, '.svelte', '', new NoopLogger());
305299
// We should have no contents
306300
expect(contents).toMatchObject([]);
307301

@@ -318,12 +312,7 @@ query {id}`);
318312
.spyOn(process.stderr, 'write')
319313
.mockImplementation(() => true);
320314

321-
const contents = baseFindGraphQLTags(
322-
text,
323-
'.svelte',
324-
'',
325-
new Logger(tmpdir(), false),
326-
);
315+
const contents = baseFindGraphQLTags(text, '.svelte', '', new NoopLogger());
327316
// We should have no contents
328317
expect(contents).toMatchObject([]);
329318

@@ -340,12 +329,7 @@ query {id}`);
340329
.spyOn(process.stderr, 'write')
341330
.mockImplementation(() => true);
342331

343-
const contents = baseFindGraphQLTags(
344-
text,
345-
'.svelte',
346-
'',
347-
new Logger(tmpdir(), false),
348-
);
332+
const contents = baseFindGraphQLTags(text, '.svelte', '', new NoopLogger());
349333
// We should have no contents
350334
expect(contents).toMatchObject([]);
351335

packages/graphql-language-service-server/src/findGraphQLTags.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { Position, Range } from 'graphql-language-service';
1717

1818
import { parse, ParserOptions, ParserPlugin } from '@babel/parser';
1919
import * as VueParser from '@vue/compiler-sfc';
20-
import { Logger } from './Logger';
20+
import type { Logger } from 'vscode-languageserver';
2121

2222
// Attempt to be as inclusive as possible of source text.
2323
const PARSER_OPTIONS: ParserOptions = {

packages/graphql-language-service-server/src/index.ts

-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ export { MessageProcessor } from './MessageProcessor';
1111

1212
export { default as startServer } from './startServer';
1313

14-
export { Logger } from './Logger';
15-
1614
export * from './GraphQLCache';
1715
export * from './parseDocument';
1816
export * from './findGraphQLTags';

packages/graphql-language-service-server/src/parseDocument.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { extname } from 'node:path';
22
import type { CachedContent } from 'graphql-language-service';
33
import { Range, Position } from 'graphql-language-service';
4+
import type { Logger } from 'vscode-languageserver';
45

56
import { findGraphQLTags, DEFAULT_TAGS } from './findGraphQLTags';
6-
import { Logger } from './Logger';
7+
import { NoopLogger } from './Logger';
78

89
export const DEFAULT_SUPPORTED_EXTENSIONS = [
910
'.js',
@@ -48,7 +49,7 @@ export function parseDocument(
4849
uri: string,
4950
fileExtensions: string[] = DEFAULT_SUPPORTED_EXTENSIONS,
5051
graphQLFileExtensions: string[] = DEFAULT_SUPPORTED_GRAPHQL_EXTENSIONS,
51-
logger: Logger = new Logger(),
52+
logger: Logger = new NoopLogger(),
5253
): CachedContent[] {
5354
// Check if the text content includes a GraphQLV query.
5455
// If the text doesn't include GraphQL queries, do not proceed.

0 commit comments

Comments
 (0)