@0xobelisk/graphql-server 1.2.0-pre.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/Dockerfile +31 -0
  2. package/EXPRESS_MIGRATION.md +176 -0
  3. package/LICENSE +92 -0
  4. package/README.md +908 -0
  5. package/dist/config/subscription-config.d.ts +47 -0
  6. package/dist/config/subscription-config.d.ts.map +1 -0
  7. package/dist/config/subscription-config.js +133 -0
  8. package/dist/config/subscription-config.js.map +1 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +217 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/plugins/all-fields-filter-plugin.d.ts +4 -0
  14. package/dist/plugins/all-fields-filter-plugin.d.ts.map +1 -0
  15. package/dist/plugins/all-fields-filter-plugin.js +132 -0
  16. package/dist/plugins/all-fields-filter-plugin.js.map +1 -0
  17. package/dist/plugins/database-introspector.d.ts +23 -0
  18. package/dist/plugins/database-introspector.d.ts.map +1 -0
  19. package/dist/plugins/database-introspector.js +96 -0
  20. package/dist/plugins/database-introspector.js.map +1 -0
  21. package/dist/plugins/enhanced-playground.d.ts +9 -0
  22. package/dist/plugins/enhanced-playground.d.ts.map +1 -0
  23. package/dist/plugins/enhanced-playground.js +97 -0
  24. package/dist/plugins/enhanced-playground.js.map +1 -0
  25. package/dist/plugins/enhanced-server-manager.d.ts +28 -0
  26. package/dist/plugins/enhanced-server-manager.d.ts.map +1 -0
  27. package/dist/plugins/enhanced-server-manager.js +232 -0
  28. package/dist/plugins/enhanced-server-manager.js.map +1 -0
  29. package/dist/plugins/index.d.ts +9 -0
  30. package/dist/plugins/index.d.ts.map +1 -0
  31. package/dist/plugins/index.js +26 -0
  32. package/dist/plugins/index.js.map +1 -0
  33. package/dist/plugins/postgraphile-config.d.ts +94 -0
  34. package/dist/plugins/postgraphile-config.d.ts.map +1 -0
  35. package/dist/plugins/postgraphile-config.js +183 -0
  36. package/dist/plugins/postgraphile-config.js.map +1 -0
  37. package/dist/plugins/query-filter.d.ts +4 -0
  38. package/dist/plugins/query-filter.d.ts.map +1 -0
  39. package/dist/plugins/query-filter.js +42 -0
  40. package/dist/plugins/query-filter.js.map +1 -0
  41. package/dist/plugins/simple-naming.d.ts +4 -0
  42. package/dist/plugins/simple-naming.d.ts.map +1 -0
  43. package/dist/plugins/simple-naming.js +79 -0
  44. package/dist/plugins/simple-naming.js.map +1 -0
  45. package/dist/plugins/welcome-page.d.ts +11 -0
  46. package/dist/plugins/welcome-page.d.ts.map +1 -0
  47. package/dist/plugins/welcome-page.js +203 -0
  48. package/dist/plugins/welcome-page.js.map +1 -0
  49. package/dist/universal-subscriptions.d.ts +32 -0
  50. package/dist/universal-subscriptions.d.ts.map +1 -0
  51. package/dist/universal-subscriptions.js +318 -0
  52. package/dist/universal-subscriptions.js.map +1 -0
  53. package/dist/utils/logger/index.d.ts +80 -0
  54. package/dist/utils/logger/index.d.ts.map +1 -0
  55. package/dist/utils/logger/index.js +232 -0
  56. package/dist/utils/logger/index.js.map +1 -0
  57. package/docker-compose.yml +87 -0
  58. package/package.json +71 -0
  59. package/server.log +62 -0
  60. package/src/config/subscription-config.ts +186 -0
  61. package/src/index.ts +239 -0
  62. package/src/plugins/README.md +123 -0
  63. package/src/plugins/all-fields-filter-plugin.ts +158 -0
  64. package/src/plugins/database-introspector.ts +126 -0
  65. package/src/plugins/enhanced-playground.ts +105 -0
  66. package/src/plugins/enhanced-server-manager.ts +282 -0
  67. package/src/plugins/index.ts +9 -0
  68. package/src/plugins/postgraphile-config.ts +226 -0
  69. package/src/plugins/query-filter.ts +50 -0
  70. package/src/plugins/simple-naming.ts +105 -0
  71. package/src/plugins/welcome-page.ts +218 -0
  72. package/src/universal-subscriptions.ts +397 -0
  73. package/src/utils/logger/README.md +193 -0
  74. package/src/utils/logger/index.ts +315 -0
  75. package/sui-indexer-schema.graphql +1004 -0
  76. package/test-express.js +124 -0
  77. package/test_listen_subscription.js +121 -0
  78. package/test_notification.js +63 -0
  79. package/tsconfig.json +28 -0
@@ -0,0 +1,193 @@
1
+ # Dubhe Logger System
2
+
3
+ High-performance logging system based on Pino, featuring object-oriented design for better understanding and extensibility.
4
+
5
+ ## Features
6
+
7
+ - 🚀 High-performance logging based on Pino
8
+ - 📝 Support for structured logging
9
+ - 🎨 Colorful pretty printing in development environment
10
+ - 📁 File logging support in production environment
11
+ - 🔧 Flexible configuration options
12
+ - 📦 Component-based log management
13
+ - 🛡️ TypeScript type safety
14
+
15
+ ## Basic Usage
16
+
17
+ ### 1. Using Predefined Component Loggers
18
+
19
+ ```typescript
20
+ import { dbLogger, serverLogger, systemLogger } from './utils/logger';
21
+
22
+ // Database operation logs
23
+ dbLogger.info('Database connection successful', { host: 'localhost', port: 5432 });
24
+ dbLogger.error('Query failed', new Error('Connection timeout'), { query: 'SELECT * FROM users' });
25
+
26
+ // Server logs
27
+ serverLogger.info('Server started', { port: 4000, env: 'development' });
28
+
29
+ // System logs
30
+ systemLogger.warn('High memory usage', { usage: '85%' });
31
+ ```
32
+
33
+ ### 2. Creating Custom Component Loggers
34
+
35
+ ```typescript
36
+ import { createComponentLogger } from './utils/logger';
37
+
38
+ const apiLogger = createComponentLogger('api');
39
+ const cacheLogger = createComponentLogger('cache');
40
+
41
+ apiLogger.info('API request', { method: 'GET', path: '/users', userId: 123 });
42
+ cacheLogger.debug('Cache hit', { key: 'user:123', ttl: 3600 });
43
+ ```
44
+
45
+ ### 3. Using Logger Class to Create Custom Instances
46
+
47
+ ```typescript
48
+ import { Logger } from './utils/logger';
49
+
50
+ // Create logger with custom configuration
51
+ const customLogger = new Logger({
52
+ level: 'debug',
53
+ service: 'my-service',
54
+ enableFileLogging: true,
55
+ logsDir: './custom-logs',
56
+ enablePrettyPrint: false
57
+ });
58
+
59
+ const myLogger = customLogger.createComponentLogger('my-component');
60
+ myLogger.info('Custom log message');
61
+ ```
62
+
63
+ ## Configuration Options
64
+
65
+ ```typescript
66
+ interface LoggerConfig {
67
+ level?: string; // Log level (debug|info|warn|error)
68
+ service?: string; // Service name
69
+ component?: string; // Component name
70
+ enableFileLogging?: boolean; // Enable file logging
71
+ logsDir?: string; // Log file directory
72
+ enablePrettyPrint?: boolean; // Enable colorful output
73
+ }
74
+ ```
75
+
76
+ ## Utility Functions
77
+
78
+ ### Performance Logging
79
+
80
+ ```typescript
81
+ import { logPerformance } from './utils/logger';
82
+
83
+ const startTime = Date.now();
84
+ // ... perform operations
85
+ logPerformance('Database query', startTime, { table: 'users', rows: 1000 });
86
+ ```
87
+
88
+ ### Database Operation Logging
89
+
90
+ ```typescript
91
+ import { logDatabaseOperation } from './utils/logger';
92
+
93
+ logDatabaseOperation('SELECT', 'users', { limit: 10, offset: 0 });
94
+ ```
95
+
96
+ ### WebSocket Event Logging
97
+
98
+ ```typescript
99
+ import { logWebSocketEvent } from './utils/logger';
100
+
101
+ logWebSocketEvent('client_connected', 5, { clientId: 'abc123' });
102
+ ```
103
+
104
+ ### GraphQL Query Logging
105
+
106
+ ```typescript
107
+ import { logGraphQLQuery } from './utils/logger';
108
+
109
+ logGraphQLQuery('query', 'query GetUsers { users { id name } }', { limit: 10 });
110
+ ```
111
+
112
+ ## Predefined Component Loggers
113
+
114
+ | Logger | Component | Purpose |
115
+ |--------|-----------|---------|
116
+ | `dbLogger` | database | Database operations |
117
+ | `serverLogger` | server | Server related |
118
+ | `wsLogger` | websocket | WebSocket connections |
119
+ | `gqlLogger` | graphql | GraphQL queries |
120
+ | `subscriptionLogger` | subscription | Subscription features |
121
+ | `systemLogger` | system | System level |
122
+ | `authLogger` | auth | Authentication |
123
+ | `perfLogger` | performance | Performance monitoring |
124
+
125
+ ## Environment Variables
126
+
127
+ - `LOG_LEVEL`: Set log level (debug|info|warn|error)
128
+ - `NODE_ENV`: Set environment mode, enables pretty printing in development
129
+
130
+ ## Log Format
131
+
132
+ ### Development Environment (Pretty Print)
133
+ ```
134
+ 2024-01-15 10:30:45 [INFO] dubhe-graphql-server [database]: Database connection successful {"host": "localhost", "port": 5432}
135
+ ```
136
+
137
+ ### Production Environment (JSON)
138
+ ```json
139
+ {"level":30,"time":"2024-01-15T10:30:45.123Z","service":"dubhe-graphql-server","component":"database","msg":"Database connection successful","host":"localhost","port":5432}
140
+ ```
141
+
142
+ ## Advanced Usage
143
+
144
+ ### Extending Logger Class
145
+
146
+ ```typescript
147
+ import { Logger, LoggerConfig } from './utils/logger';
148
+
149
+ class CustomLogger extends Logger {
150
+ constructor(config: LoggerConfig) {
151
+ super(config);
152
+ }
153
+
154
+ // Add custom methods
155
+ public audit(action: string, userId: string, meta?: any) {
156
+ const auditLogger = this.createComponentLogger('audit');
157
+ auditLogger.info(`User action: ${action}`, { userId, timestamp: new Date().toISOString(), ...meta });
158
+ }
159
+ }
160
+
161
+ const logger = new CustomLogger({ service: 'audit-service' });
162
+ logger.audit('login', 'user123', { ip: '192.168.1.1' });
163
+ ```
164
+
165
+ ### Getting Raw Pino Instance
166
+
167
+ ```typescript
168
+ import { Logger } from './utils/logger';
169
+
170
+ const logger = new Logger();
171
+ const pinoInstance = logger.getPinoInstance();
172
+
173
+ // Use Pino API directly
174
+ pinoInstance.info({ customField: 'value' }, 'Using Pino directly');
175
+ ```
176
+
177
+ ## Migration Guide
178
+
179
+ Migrating from winston to the new Logger system:
180
+
181
+ ### Before (Winston)
182
+ ```typescript
183
+ import logger from './logger';
184
+ logger.info('Message', { meta: 'data' });
185
+ ```
186
+
187
+ ### Now (Pino + Class)
188
+ ```typescript
189
+ import { systemLogger } from './utils/logger';
190
+ systemLogger.info('Message', { meta: 'data' });
191
+ ```
192
+
193
+ Most APIs remain compatible, just need to update import paths.
@@ -0,0 +1,315 @@
1
+ import pino from 'pino';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+
5
+ export interface LoggerConfig {
6
+ level?: string;
7
+ service?: string;
8
+ component?: string;
9
+ enableFileLogging?: boolean;
10
+ logsDir?: string;
11
+ }
12
+
13
+ export interface ComponentLoggerMethods {
14
+ debug: (message: string, meta?: any) => void;
15
+ info: (message: string, meta?: any) => void;
16
+ warn: (message: string, meta?: any) => void;
17
+ error: (message: string, error?: any, meta?: any) => void;
18
+ }
19
+
20
+ /**
21
+ * 基于Pino的高性能日志系统
22
+ */
23
+ export class Logger {
24
+ private pinoInstance: pino.Logger;
25
+ private config: Required<LoggerConfig>;
26
+
27
+ constructor(config: LoggerConfig = {}) {
28
+ this.config = {
29
+ level: config.level || process.env.LOG_LEVEL || 'info',
30
+ service: config.service || 'dubhe-graphql-server',
31
+ component: config.component || 'default',
32
+ enableFileLogging: config.enableFileLogging !== false,
33
+ logsDir: config.logsDir || path.join(process.cwd(), 'logs'),
34
+ };
35
+
36
+ this.ensureLogsDirectory();
37
+ this.pinoInstance = this.createPinoInstance();
38
+ this.setupExceptionHandlers();
39
+ }
40
+
41
+ /**
42
+ * 确保日志目录存在
43
+ */
44
+ private ensureLogsDirectory(): void {
45
+ if (
46
+ this.config.enableFileLogging &&
47
+ !fs.existsSync(this.config.logsDir)
48
+ ) {
49
+ fs.mkdirSync(this.config.logsDir, { recursive: true });
50
+ }
51
+ }
52
+
53
+ /**
54
+ * 创建Pino实例
55
+ */
56
+ private createPinoInstance(): pino.Logger {
57
+ const pinoOptions: pino.LoggerOptions = {
58
+ level: this.config.level,
59
+ base: {
60
+ service: this.config.service,
61
+ pid: process.pid,
62
+ },
63
+ timestamp: pino.stdTimeFunctions.isoTime,
64
+ formatters: {
65
+ level(label: string) {
66
+ return { level: label };
67
+ },
68
+ },
69
+ serializers: {
70
+ error: pino.stdSerializers.err,
71
+ },
72
+ };
73
+
74
+ // 如果启用文件日志,使用multistream
75
+ if (this.config.enableFileLogging) {
76
+ const streams = [
77
+ // Pretty打印到控制台
78
+ {
79
+ stream: pino.transport({
80
+ target: 'pino-pretty',
81
+ options: {
82
+ colorize: true,
83
+ translateTime: 'yyyy-mm-dd HH:MM:ss.l',
84
+ ignore: 'pid,hostname,service,component',
85
+ messageFormat: '[{component}]: {msg}',
86
+ singleLine: true,
87
+ hideObject: false,
88
+ },
89
+ }),
90
+ },
91
+ // JSON格式到文件
92
+ {
93
+ stream: pino.destination({
94
+ dest: path.join(this.config.logsDir, 'combined.log'),
95
+ sync: false,
96
+ }),
97
+ },
98
+ ];
99
+
100
+ return pino(pinoOptions, pino.multistream(streams));
101
+ }
102
+
103
+ // 只输出到控制台的pretty格式
104
+ return pino({
105
+ ...pinoOptions,
106
+ transport: {
107
+ target: 'pino-pretty',
108
+ options: {
109
+ colorize: true,
110
+ translateTime: 'yyyy-mm-dd HH:MM:ss.l',
111
+ ignore: 'pid,hostname,service',
112
+ messageFormat: '[{component}]: {msg}',
113
+ singleLine: true,
114
+ hideObject: false,
115
+ },
116
+ },
117
+ });
118
+ }
119
+
120
+ /**
121
+ * 设置异常处理器
122
+ */
123
+ private setupExceptionHandlers(): void {
124
+ process.on('uncaughtException', error => {
125
+ this.pinoInstance.fatal({ error }, 'Uncaught Exception');
126
+ process.exit(1);
127
+ });
128
+
129
+ process.on('unhandledRejection', (reason, promise) => {
130
+ this.pinoInstance.fatal(
131
+ { reason, promise },
132
+ 'Unhandled Promise Rejection'
133
+ );
134
+ process.exit(1);
135
+ });
136
+ }
137
+
138
+ /**
139
+ * 创建带组件上下文的logger
140
+ */
141
+ public createComponentLogger(component: string): ComponentLoggerMethods {
142
+ const componentLogger = this.pinoInstance.child({ component });
143
+
144
+ return {
145
+ debug: (message: string, meta?: any) =>
146
+ componentLogger.debug(meta || {}, message),
147
+ info: (message: string, meta?: any) =>
148
+ componentLogger.info(meta || {}, message),
149
+ warn: (message: string, meta?: any) =>
150
+ componentLogger.warn(meta || {}, message),
151
+ error: (message: string, error?: any, meta?: any) => {
152
+ const errorData =
153
+ error instanceof Error
154
+ ? {
155
+ error: {
156
+ message: error.message,
157
+ stack: error.stack,
158
+ name: error.name,
159
+ },
160
+ ...meta,
161
+ }
162
+ : { error, ...meta };
163
+ componentLogger.error(errorData, message);
164
+ },
165
+ };
166
+ }
167
+
168
+ /**
169
+ * 获取原始Pino实例
170
+ */
171
+ public getPinoInstance(): pino.Logger {
172
+ return this.pinoInstance;
173
+ }
174
+
175
+ /**
176
+ * 记录性能指标
177
+ */
178
+ public logPerformance(
179
+ operation: string,
180
+ startTime: number,
181
+ meta?: any
182
+ ): void {
183
+ const duration = Date.now() - startTime;
184
+ const perfLogger = this.createComponentLogger('performance');
185
+ perfLogger.info(operation, {
186
+ duration: `${duration}ms`,
187
+ ...meta,
188
+ });
189
+ }
190
+
191
+ /**
192
+ * 记录Express HTTP请求
193
+ */
194
+ public logExpress(
195
+ method: string,
196
+ path: string,
197
+ statusCode: number,
198
+ startTime: number,
199
+ meta?: any
200
+ ): void {
201
+ const duration = Date.now() - startTime;
202
+ const httpLogger = this.createComponentLogger('express');
203
+ const message = `${method} ${path} - ${statusCode} (${duration}ms)`;
204
+
205
+ // 根据状态码选择日志级别
206
+ if (statusCode >= 500) {
207
+ httpLogger.error(message, meta);
208
+ } else if (statusCode >= 400) {
209
+ httpLogger.warn(message, meta);
210
+ } else {
211
+ httpLogger.info(message, meta);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * 记录数据库操作
217
+ */
218
+ public logDatabaseOperation(
219
+ operation: string,
220
+ table?: string,
221
+ meta?: any
222
+ ): void {
223
+ const dbLogger = this.createComponentLogger('database');
224
+ dbLogger.info(`Database operation: ${operation}`, {
225
+ table,
226
+ ...meta,
227
+ });
228
+ }
229
+
230
+ /**
231
+ * 记录WebSocket事件
232
+ */
233
+ public logWebSocketEvent(
234
+ event: string,
235
+ clientCount?: number,
236
+ meta?: any
237
+ ): void {
238
+ const wsLogger = this.createComponentLogger('websocket');
239
+ wsLogger.info(`WebSocket event: ${event}`, {
240
+ clientCount,
241
+ ...meta,
242
+ });
243
+ }
244
+
245
+ /**
246
+ * 记录GraphQL查询
247
+ */
248
+ public logGraphQLQuery(
249
+ operation: string,
250
+ query?: string,
251
+ variables?: any
252
+ ): void {
253
+ const gqlLogger = this.createComponentLogger('graphql');
254
+ gqlLogger.info(`GraphQL ${operation}`, {
255
+ query:
256
+ query?.substring(0, 200) +
257
+ (query && query.length > 200 ? '...' : ''),
258
+ variableCount: variables ? Object.keys(variables).length : 0,
259
+ });
260
+ }
261
+ }
262
+
263
+ // 创建默认logger实例
264
+ const defaultLogger = new Logger();
265
+
266
+ // 导出预定义的组件logger(保持向后兼容)
267
+ export const dbLogger = defaultLogger.createComponentLogger('database');
268
+ export const serverLogger = defaultLogger.createComponentLogger('server');
269
+ export const httpLogger = defaultLogger.createComponentLogger('express');
270
+ export const wsLogger = defaultLogger.createComponentLogger('websocket');
271
+ export const gqlLogger = defaultLogger.createComponentLogger('graphql');
272
+ export const subscriptionLogger =
273
+ defaultLogger.createComponentLogger('subscription');
274
+ export const systemLogger = defaultLogger.createComponentLogger('system');
275
+ export const authLogger = defaultLogger.createComponentLogger('auth');
276
+ export const perfLogger = defaultLogger.createComponentLogger('performance');
277
+
278
+ // 导出工具函数(保持向后兼容)
279
+ export const createComponentLogger = (component: string) =>
280
+ defaultLogger.createComponentLogger(component);
281
+
282
+ export const logPerformance = (
283
+ operation: string,
284
+ startTime: number,
285
+ meta?: any
286
+ ) => defaultLogger.logPerformance(operation, startTime, meta);
287
+
288
+ export const logExpress = (
289
+ method: string,
290
+ path: string,
291
+ statusCode: number,
292
+ startTime: number,
293
+ meta?: any
294
+ ) => defaultLogger.logExpress(method, path, statusCode, startTime, meta);
295
+
296
+ export const logDatabaseOperation = (
297
+ operation: string,
298
+ table?: string,
299
+ meta?: any
300
+ ) => defaultLogger.logDatabaseOperation(operation, table, meta);
301
+
302
+ export const logWebSocketEvent = (
303
+ event: string,
304
+ clientCount?: number,
305
+ meta?: any
306
+ ) => defaultLogger.logWebSocketEvent(event, clientCount, meta);
307
+
308
+ export const logGraphQLQuery = (
309
+ operation: string,
310
+ query?: string,
311
+ variables?: any
312
+ ) => defaultLogger.logGraphQLQuery(operation, query, variables);
313
+
314
+ // 默认导出(保持向后兼容)
315
+ export default defaultLogger.getPinoInstance();