rl-rockcli 0.0.2 → 0.0.3

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 (75) hide show
  1. package/README.md +400 -0
  2. package/index.js +51 -21
  3. package/package.json +1 -1
  4. package/commands/log/core/constants.js +0 -237
  5. package/commands/log/core/display.js +0 -370
  6. package/commands/log/core/search.js +0 -330
  7. package/commands/log/core/tail.js +0 -216
  8. package/commands/log/core/utils.js +0 -424
  9. package/commands/log.js +0 -298
  10. package/commands/sandbox/core/log-bridge.js +0 -119
  11. package/commands/sandbox/core/replay/analyzer.js +0 -311
  12. package/commands/sandbox/core/replay/batch-orchestrator.js +0 -536
  13. package/commands/sandbox/core/replay/batch-task.js +0 -369
  14. package/commands/sandbox/core/replay/concurrent-display.js +0 -70
  15. package/commands/sandbox/core/replay/concurrent-orchestrator.js +0 -170
  16. package/commands/sandbox/core/replay/data-source.js +0 -86
  17. package/commands/sandbox/core/replay/display.js +0 -231
  18. package/commands/sandbox/core/replay/executor.js +0 -634
  19. package/commands/sandbox/core/replay/history-fetcher.js +0 -124
  20. package/commands/sandbox/core/replay/index.js +0 -338
  21. package/commands/sandbox/core/replay/loghouse-data-source.js +0 -177
  22. package/commands/sandbox/core/replay/pid-mapping.js +0 -26
  23. package/commands/sandbox/core/replay/request.js +0 -109
  24. package/commands/sandbox/core/replay/worker.js +0 -166
  25. package/commands/sandbox/core/session.js +0 -346
  26. package/commands/sandbox/log-bridge.js +0 -2
  27. package/commands/sandbox/ray.js +0 -2
  28. package/commands/sandbox/replay/analyzer.js +0 -311
  29. package/commands/sandbox/replay/batch-orchestrator.js +0 -536
  30. package/commands/sandbox/replay/batch-task.js +0 -369
  31. package/commands/sandbox/replay/concurrent-display.js +0 -70
  32. package/commands/sandbox/replay/concurrent-orchestrator.js +0 -170
  33. package/commands/sandbox/replay/display.js +0 -231
  34. package/commands/sandbox/replay/executor.js +0 -634
  35. package/commands/sandbox/replay/history-fetcher.js +0 -118
  36. package/commands/sandbox/replay/index.js +0 -338
  37. package/commands/sandbox/replay/pid-mapping.js +0 -26
  38. package/commands/sandbox/replay/request.js +0 -109
  39. package/commands/sandbox/replay/worker.js +0 -166
  40. package/commands/sandbox/replay.js +0 -2
  41. package/commands/sandbox/session.js +0 -2
  42. package/commands/sandbox-original.js +0 -1393
  43. package/commands/sandbox.js +0 -499
  44. package/help/help.json +0 -1071
  45. package/help/middleware.js +0 -71
  46. package/help/renderer.js +0 -800
  47. package/lib/plugin-context.js +0 -40
  48. package/sdks/sandbox/core/client.js +0 -845
  49. package/sdks/sandbox/core/config.js +0 -70
  50. package/sdks/sandbox/core/types.js +0 -74
  51. package/sdks/sandbox/httpLogger.js +0 -251
  52. package/sdks/sandbox/index.js +0 -9
  53. package/utils/asciiArt.js +0 -138
  54. package/utils/bun-compat.js +0 -59
  55. package/utils/ciPipelines.js +0 -138
  56. package/utils/cli.js +0 -17
  57. package/utils/command-router.js +0 -79
  58. package/utils/configManager.js +0 -503
  59. package/utils/dependency-resolver.js +0 -135
  60. package/utils/eagleeye_traceid.js +0 -151
  61. package/utils/envDetector.js +0 -78
  62. package/utils/execution_logger.js +0 -415
  63. package/utils/featureManager.js +0 -68
  64. package/utils/firstTimeTip.js +0 -44
  65. package/utils/hook-manager.js +0 -125
  66. package/utils/http-logger.js +0 -264
  67. package/utils/i18n.js +0 -139
  68. package/utils/image-progress.js +0 -159
  69. package/utils/logger.js +0 -154
  70. package/utils/plugin-loader.js +0 -124
  71. package/utils/plugin-manager.js +0 -348
  72. package/utils/ray_cli_wrapper.js +0 -746
  73. package/utils/sandbox-client.js +0 -419
  74. package/utils/terminal.js +0 -32
  75. package/utils/tips.js +0 -106
@@ -1,237 +0,0 @@
1
- // 日志显示字段配置
2
- const DISPLAY_FIELDS = [
3
- 'timestamp',
4
- 'time',
5
- 'time_iso8601',
6
- 'ms',
7
- 'level',
8
- 'sandbox_id',
9
- 'trace_id',
10
- 'sent_http_request_id',
11
- 'request_id',
12
- 'callId',
13
- 'logger',
14
- 'thread',
15
- 'field',
16
- 'method',
17
- 'class',
18
- 'request_method',
19
- 'url',
20
- 'request_uri',
21
- 'host',
22
- 'status',
23
- 'status_code',
24
- 'process_time',
25
- 'request_time_usec',
26
- 'request_length',
27
- 'body_bytes_sent',
28
- 'upstream_response_tim',
29
- 'message',
30
- 'request',
31
- "headers",
32
- "http_Authorization",
33
- "http_x_cluster",
34
- "http_user_id",
35
- "http_x_experiment_id",
36
- "http_user_agent",
37
- 'request_body',
38
- 'response',
39
- 'filename',
40
- 'lineno',
41
- 'site',
42
- 'exc_info',
43
- 'exception',
44
- 'command_id',
45
- 'event',
46
- 'content',
47
- ];
48
-
49
- // 字段颜色映射(ANSI 颜色代码)
50
- // 1. 内置字段(@ 开头):灰色 - 系统元数据,通常不需要关注
51
- // 2. 一般情况不需要关注的字段:灰色 - 辅助信息,低价值
52
- // 3. 普通字段:青色 - 常规字段,有一定价值
53
- // 4. 重点字段:粗体青色 - 核心标识,最重要的字段
54
- const FIELD_COLOR_MAP = {
55
- // 1. 内置字段(@ 开头)- 灰色
56
- '@timestamp': '\x1b[0;90m',
57
- '@source': '\x1b[0;90m',
58
- '@app_group': '\x1b[0;90m',
59
- '@hostname': '\x1b[0;90m',
60
- '@filename': '\x1b[0;90m',
61
- '@packId': '\x1b[0;90m',
62
- '@logGroupOrder': '\x1b[0;90m',
63
- '@topic': '\x1b[0;90m',
64
- '@app_stage': '\x1b[0;90m',
65
- '@site': '\x1b[0;90m',
66
-
67
- // 2. 一般情况不需要关注的字段 - 灰色
68
- 'ms': '\x1b[0;90m',
69
- 'logger': '\x1b[0;90m',
70
- 'lineno': '\x1b[0;90m',
71
- 'site': '\x1b[0;90m',
72
- 'command_id': '\x1b[0;90m',
73
- 'sent_http_request_id': '\x1b[0;90m',
74
-
75
- // 3. 普通字段 - 青色
76
- 'method': '\x1b[0;36m',
77
- 'request_method': '\x1b[0;36m',
78
- 'field': '\x1b[0;36m',
79
- 'url': '\x1b[0;36m',
80
- 'request_uri': '\x1b[0;36m',
81
- 'status_code': '\x1b[0;36m',
82
- 'process_time': '\x1b[0;36m',
83
- 'request': '\x1b[0;36m',
84
- 'request_body': '\x1b[0;36m',
85
- 'response': '\x1b[0;36m',
86
- 'filename': '\x1b[0;36m',
87
- 'event': '\x1b[0;36m',
88
- 'content': '\x1b[0;36m',
89
- 'sandbox_id': '\x1b[0;36m',
90
- 'trace_id': '\x1b[0;36m',
91
-
92
- // 4. 重点字段 - 粗体青色
93
- 'timestamp': '\x1b[1;36m',
94
- 'time': '\x1b[1;36m',
95
- 'time_iso8601': '\x1b[1;36m',
96
- 'level': '\x1b[1;36m',
97
- 'message': '\x1b[1;36m',
98
- 'exc_info': '\x1b[1;31m', // 异常信息 - 红色粗体
99
- 'exception': '\x1b[1;31m', // 异常 - 红色粗体
100
- 'error': '\x1b[1;31m', // 错误 - 红色粗体
101
- };
102
-
103
- // 默认字段颜色
104
- const DEFAULT_FIELD_COLOR = '\x1b[0;90m';
105
-
106
- // 字段黑名单(格式化模式下不显示)
107
- const BLACKLIST_FIELDS = [
108
- 'sent_http_X_App_Id',
109
- 'scheme',
110
- 'remote_user',
111
- 'http_x_opensearch_rem',
112
- 'http_x_opensearch_sec',
113
- 'sent_http_Application',
114
- 'http_Content_Md5',
115
- 'http_date',
116
- 'sent_http_X_App_Name',
117
- 'http_Authorization',
118
- 'http_x_opensearch_non',
119
- 'sent_http_X_Aliyun_Us',
120
- 'sent_http_X_AppGroup_',
121
- 'upstream_response_tim',
122
- ];
123
-
124
- // 需要截断的字段
125
- const TRUNCATE_FIELDS = ['message', 'content', 'event'];
126
-
127
- // Group by field mapping
128
- const GROUP_BY_FIELDS = {
129
- 'file': '@filename',
130
- 'ip': '@source',
131
- 'app': '@app_group',
132
- 'hostname': '@hostname',
133
- 'cluster': '_cluster',
134
- };
135
-
136
- // Group by field display labels
137
- const GROUP_BY_LABELS = {
138
- '@filename': 'File',
139
- '@source': 'IP',
140
- '@app_group': 'App',
141
- '@hostname': 'Machine',
142
- '_cluster': 'Cluster',
143
- };
144
-
145
- // ANSI 颜色代码
146
- const ANSI_COLORS = {
147
- RESET: '\x1b[0m',
148
- BOLD: '\x1b[1m',
149
- CYAN: '\x1b[36m',
150
- YELLOW: '\x1b[33m',
151
- GREEN: '\x1b[32m',
152
- MAGENTA: '\x1b[35m',
153
- BLUE: '\x1b[34m',
154
- RED: '\x1b[31m',
155
- GRAY: '\x1b[90m',
156
- };
157
-
158
- // 查询时间范围(分钟)
159
- const TIME_RANGES = [15, 60, 180, 720, 1800, 43200];
160
-
161
- // 分页大小
162
- const PAGE_SIZE = 1000;
163
-
164
- // 日志文件名
165
- // 注意:内网专有日志路径已移到 config/internal_log_config.json
166
- const LOG_FILES = {
167
- // 保留空对象,由具体命令从配置文件加载
168
- };
169
-
170
-
171
- // 字段补全列表(用于 -f 参数的自动补全)
172
- const FIELD_COMPLETION_LIST = [
173
- // 系统内置字段(@ 开头)
174
- '@filename',
175
- '@source',
176
- '@app_group',
177
- '@hostname',
178
- '@timestamp',
179
- '@packId',
180
- '@logGroupOrder',
181
- '@topic',
182
- '@app_stage',
183
- '@site',
184
-
185
- // 常规字段
186
- 'status',
187
- 'status_code',
188
- 'level',
189
- 'message',
190
- 'method',
191
- 'request_method',
192
- 'url',
193
- 'request_uri',
194
- 'host',
195
- 'sandbox_id',
196
- 'trace_id',
197
- 'thread',
198
- 'logger',
199
- 'field',
200
- 'process_time',
201
- 'request_time_usec',
202
- 'request_length',
203
- 'body_bytes_sent',
204
- 'request',
205
- 'headers',
206
- 'http_Authorization',
207
- 'http_x_cluster',
208
- 'http_user_id',
209
- 'http_x_experiment_id',
210
- 'http_user_agent',
211
- 'request_body',
212
- 'response',
213
- 'filename',
214
- 'lineno',
215
- 'site',
216
- 'exc_info',
217
- 'exception',
218
- 'command_id',
219
- 'event',
220
- 'content',
221
- 'error',
222
- ];
223
-
224
- module.exports = {
225
- DISPLAY_FIELDS,
226
- FIELD_COLOR_MAP,
227
- DEFAULT_FIELD_COLOR,
228
- BLACKLIST_FIELDS,
229
- TRUNCATE_FIELDS,
230
- GROUP_BY_FIELDS,
231
- GROUP_BY_LABELS,
232
- ANSI_COLORS,
233
- TIME_RANGES,
234
- PAGE_SIZE,
235
- LOG_FILES,
236
- FIELD_COMPLETION_LIST,
237
- };
@@ -1,370 +0,0 @@
1
- const { DISPLAY_FIELDS, FIELD_COLOR_MAP, DEFAULT_FIELD_COLOR, TRUNCATE_FIELDS, ANSI_COLORS, GROUP_BY_FIELDS } = require('./constants');
2
- const { isBlacklisted } = require('./utils');
3
-
4
- // 分组字段显示名称
5
- const GROUP_BY_LABELS = {
6
- '@filename': 'File',
7
- '@source': 'IP',
8
- '@app_group': 'App',
9
- '@hostname': 'Machine',
10
- '_cluster': 'Cluster',
11
- };
12
-
13
- function highlightKeyword(text, keyword) {
14
- if (!keyword || !text) return text;
15
-
16
- const HIGHLIGHT_BG = '\x1b[43m';
17
- const HIGHLIGHT_FG = '\x1b[30m';
18
- const RESET = '\x1b[0m\x1b[49m';
19
-
20
- const keywords = Array.isArray(keyword) ? keyword : [keyword];
21
-
22
- let result = text;
23
- keywords.forEach(kw => {
24
- if (kw && typeof kw === 'string') {
25
- const escapedKeyword = kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
26
- const regex = new RegExp(`(${escapedKeyword})`, 'gi');
27
- result = result.replace(regex, `${HIGHLIGHT_BG}${HIGHLIGHT_FG}$1${RESET}`);
28
- }
29
- });
30
-
31
- return result;
32
- }
33
-
34
- function highlightFieldName(fieldName, keyword, originalColor) {
35
- if (!keyword || !fieldName) return originalColor + fieldName + '\x1b[0m';
36
-
37
- const HIGHLIGHT_BG = '\x1b[43m';
38
- const HIGHLIGHT_FG = '\x1b[30m';
39
- const RESET = '\x1b[0m\x1b[49m';
40
-
41
- const keywords = Array.isArray(keyword) ? keyword : [keyword];
42
-
43
- const shouldHighlight = keywords.some(kw => kw && typeof kw === 'string' && fieldName === kw);
44
-
45
- if (shouldHighlight) {
46
- return `${HIGHLIGHT_BG}${HIGHLIGHT_FG}${fieldName}${RESET}`;
47
- }
48
-
49
- return originalColor + fieldName + '\x1b[0m';
50
- }
51
-
52
- function truncateValue(value, fieldName, truncate) {
53
- if (truncate === 0) {
54
- return value;
55
- }
56
-
57
- if (TRUNCATE_FIELDS.includes(fieldName)) {
58
- const strValue = String(value);
59
- if (strValue.length > truncate) {
60
- return strValue.substring(0, truncate) + '...[truncated]';
61
- }
62
- }
63
- return value;
64
- }
65
-
66
- function applyHighlightAndTruncate(value, fieldName, truncate, keyword, highlight) {
67
- let strValue = typeof value === 'object' ? JSON.stringify(value) : String(value);
68
-
69
- strValue = truncateValue(strValue, fieldName, truncate);
70
-
71
- if (keyword && highlight) {
72
- strValue = highlightKeyword(strValue, keyword);
73
- }
74
-
75
- return strValue;
76
- }
77
-
78
- function getFieldColor(fieldName, isTTY) {
79
- if (!isTTY) return '';
80
- return FIELD_COLOR_MAP[fieldName] || DEFAULT_FIELD_COLOR;
81
- }
82
-
83
- function formatLogEntry(log, raw, logFormat, columns, truncate, keyword, highlight) {
84
- const isTTY = process.stdout.isTTY;
85
- const RESET = ANSI_COLORS.RESET;
86
-
87
- let columnFilter = null;
88
- if (columns) {
89
- columnFilter = columns.split(',').map(c => c.trim());
90
- }
91
-
92
- if (logFormat === 'json') {
93
- const output = {};
94
- Object.keys(log).forEach(key => {
95
- if (key.startsWith('@')) return;
96
- if (columnFilter && !columnFilter.includes(key)) return;
97
- if (log[key] === null || log[key] === undefined) return;
98
- output[key] = log[key];
99
- });
100
- console.log(JSON.stringify(output));
101
- return;
102
- }
103
-
104
- if (logFormat === 'columns') {
105
- const fieldsToDisplay = columnFilter || Object.keys(log).filter(k => !k.startsWith('@'));
106
- fieldsToDisplay.forEach(key => {
107
- if (log[key] === null || log[key] === undefined) return;
108
- const color = getFieldColor(key, isTTY);
109
- const value = applyHighlightAndTruncate(log[key], key, truncate, keyword, highlight);
110
- const highlightedKey = highlightFieldName(key, keyword && highlight ? keyword : [], color);
111
- console.log(`${highlightedKey}: ${value}`);
112
- });
113
- console.log('');
114
- return;
115
- }
116
-
117
- let formattedFields = [];
118
-
119
- if (raw) {
120
- const atFields = Object.keys(log).filter(fieldName =>
121
- fieldName.startsWith('@') &&
122
- (!columnFilter || columnFilter.includes(fieldName)) &&
123
- log[fieldName] !== null &&
124
- log[fieldName] !== undefined
125
- ).sort();
126
-
127
- const displayFields = DISPLAY_FIELDS.filter(fieldName =>
128
- !fieldName.startsWith('@') &&
129
- log.hasOwnProperty(fieldName) &&
130
- log[fieldName] !== null &&
131
- log[fieldName] !== undefined &&
132
- (!columnFilter || columnFilter.includes(fieldName))
133
- );
134
-
135
- const otherFields = Object.keys(log).filter(fieldName =>
136
- !fieldName.startsWith('@') &&
137
- !DISPLAY_FIELDS.includes(fieldName) &&
138
- (!columnFilter || columnFilter.includes(fieldName)) &&
139
- log[fieldName] !== null &&
140
- log[fieldName] !== undefined
141
- ).sort();
142
-
143
- atFields.forEach(fieldName => {
144
- const color = getFieldColor(fieldName, isTTY);
145
- const value = applyHighlightAndTruncate(log[fieldName], fieldName, truncate, keyword, highlight);
146
- const highlightedKey = highlightFieldName(fieldName, keyword && highlight ? keyword : [], color);
147
-
148
- let formattedValue = value;
149
- if (typeof value === 'string' && (value.includes(' ') || value.includes('"') || value.includes("'") || value.includes('=') || value.includes('\n') || value.includes('\r'))) {
150
- formattedValue = `"${value.replace(/"/g, '\\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r')}"`;
151
- }
152
-
153
- formattedFields.push(`${highlightedKey}=${formattedValue}${RESET}`);
154
- });
155
-
156
- displayFields.forEach(fieldName => {
157
- const color = getFieldColor(fieldName, isTTY);
158
- const value = applyHighlightAndTruncate(log[fieldName], fieldName, truncate, keyword, highlight);
159
- const highlightedKey = highlightFieldName(fieldName, keyword && highlight ? keyword : [], color);
160
-
161
- let formattedValue = value;
162
- if (typeof value === 'string' && (value.includes(' ') || value.includes('"') || value.includes("'") || value.includes('=') || value.includes('\n') || value.includes('\r'))) {
163
- formattedValue = `"${value.replace(/"/g, '\\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r')}"`;
164
- }
165
-
166
- formattedFields.push(`${highlightedKey}=${formattedValue}${RESET}`);
167
- });
168
-
169
- otherFields.forEach(fieldName => {
170
- const color = getFieldColor(fieldName, isTTY);
171
- const value = applyHighlightAndTruncate(log[fieldName], fieldName, truncate, keyword, highlight);
172
- const highlightedKey = highlightFieldName(fieldName, keyword && highlight ? keyword : [], color);
173
-
174
- let formattedValue = value;
175
- if (typeof value === 'string' && (value.includes(' ') || value.includes('"') || value.includes("'") || value.includes('=') || value.includes('\n') || value.includes('\r'))) {
176
- formattedValue = `"${value.replace(/"/g, '\\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r')}"`;
177
- }
178
-
179
- formattedFields.push(`${highlightedKey}=${formattedValue}${RESET}`);
180
- });
181
- } else {
182
- const fieldsToDisplay = columnFilter || DISPLAY_FIELDS;
183
-
184
- fieldsToDisplay.forEach(fieldName => {
185
- if (!log.hasOwnProperty(fieldName)) return;
186
- if (!raw && isBlacklisted(fieldName)) return;
187
- if (log[fieldName] === null || log[fieldName] === undefined) return;
188
-
189
- const color = getFieldColor(fieldName, isTTY);
190
- const value = applyHighlightAndTruncate(log[fieldName], fieldName, truncate, keyword, highlight);
191
- const highlightedKey = highlightFieldName(fieldName, keyword && highlight ? keyword : [], color);
192
-
193
- let formattedValue = value;
194
- if (typeof value === 'string' && (value.includes(' ') || value.includes('"') || value.includes("'") || value.includes('=') || value.includes('\n') || value.includes('\r'))) {
195
- formattedValue = `"${value.replace(/"/g, '\\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r')}"`;
196
- }
197
-
198
- formattedFields.push(`${highlightedKey}=${formattedValue}${RESET}`);
199
- });
200
- }
201
-
202
- if (formattedFields.length > 0) {
203
- console.log(formattedFields.join(' '));
204
- }
205
- }
206
-
207
- function displayLogsWithContext(logs, raw, logFormat, multilines, columns, truncate, keyword, highlight, showContextSeparators, groupByFields = null) {
208
- if (!logs || logs.length === 0) {
209
- return;
210
- }
211
-
212
- if (!showContextSeparators) {
213
- displayLogs(logs, raw, logFormat, multilines, columns, truncate, keyword, highlight, groupByFields);
214
- return;
215
- }
216
-
217
- const isTTY = process.stdout.isTTY;
218
- const CONTEXT_SEPARATOR = isTTY ? '\x1b[90m--\x1b[0m' : '--';
219
-
220
- const { areLogsConsecutive } = require('./utils');
221
- let previousLog = null;
222
- const logsToDisplay = [];
223
-
224
- logs.forEach((log) => {
225
- if (previousLog !== null && !areLogsConsecutive(previousLog, log)) {
226
- logsToDisplay.push({ _isSeparator: true });
227
- }
228
- logsToDisplay.push(log);
229
- previousLog = log;
230
- });
231
-
232
- logsToDisplay.forEach((item) => {
233
- if (item._isSeparator) {
234
- console.log(CONTEXT_SEPARATOR);
235
- } else {
236
- formatLogEntry(item, raw, logFormat, columns, truncate, keyword, highlight);
237
- }
238
- });
239
- }
240
-
241
- function displayLogs(logs, raw, logFormat, multilines, columns, truncate, keyword, highlight, groupByFields = null) {
242
- if (!logs || logs.length === 0) {
243
- return;
244
- }
245
-
246
- const isTTY = process.stdout.isTTY;
247
- const RESET = ANSI_COLORS.RESET;
248
-
249
- let columnFilter = null;
250
- if (columns) {
251
- columnFilter = columns.split(',').map(c => c.trim());
252
- }
253
-
254
- const resolvedGroupByFields = groupByFields
255
- ? groupByFields.map(field => GROUP_BY_FIELDS[field] || field)
256
- : [];
257
-
258
- let sortedLogs = logs;
259
- if (resolvedGroupByFields.length > 0) {
260
- sortedLogs = [...logs].sort((a, b) => {
261
- for (const field of resolvedGroupByFields) {
262
- const valA = a[field] || 'unknown';
263
- const valB = b[field] || 'unknown';
264
- if (valA !== valB) {
265
- return String(valA).localeCompare(String(valB));
266
- }
267
- }
268
- const timeA = parseInt(a['@timestamp']) || 0;
269
- const timeB = parseInt(b['@timestamp']) || 0;
270
- return timeA - timeB;
271
- });
272
- }
273
-
274
- let previousGroupValues = resolvedGroupByFields.map(() => null);
275
-
276
- sortedLogs.forEach((log, index) => {
277
- const currentGroupValues = resolvedGroupByFields.map(field => log[field] || 'unknown');
278
-
279
- if (resolvedGroupByFields.length > 0) {
280
- const isFirstLog = index === 0;
281
- const hasChanged = !isFirstLog && currentGroupValues.some((value, i) => value !== previousGroupValues[i]);
282
-
283
- if (hasChanged || isFirstLog) {
284
- if (!isFirstLog) {
285
- console.log('');
286
- if (isTTY) {
287
- console.log('\x1b[90m' + '─'.repeat(80) + '\x1b[0m');
288
- } else {
289
- console.log('─'.repeat(80));
290
- }
291
- }
292
-
293
- resolvedGroupByFields.forEach((field, i) => {
294
- if (isFirstLog || currentGroupValues[i] !== previousGroupValues[i]) {
295
- const label = GROUP_BY_LABELS[field] || field;
296
- const value = currentGroupValues[i];
297
- if (isTTY) {
298
- console.log('\x1b[36;1m' + `📦 ${label}: ${value}` + '\x1b[0m');
299
- } else {
300
- console.log(`${label}: ${value}`);
301
- }
302
- }
303
- });
304
- }
305
- }
306
-
307
- if (multilines && logFormat !== 'columns') {
308
- let fieldsToDisplay;
309
-
310
- if (raw) {
311
- if (columnFilter) {
312
- fieldsToDisplay = columnFilter;
313
- } else {
314
- const atFields = Object.keys(log).filter(fieldName =>
315
- fieldName.startsWith('@') &&
316
- log[fieldName] !== null &&
317
- log[fieldName] !== undefined
318
- ).sort();
319
-
320
- const displayFields = DISPLAY_FIELDS.filter(fieldName =>
321
- !fieldName.startsWith('@') &&
322
- log.hasOwnProperty(fieldName) &&
323
- log[fieldName] !== null &&
324
- log[fieldName] !== undefined
325
- );
326
-
327
- const otherFields = Object.keys(log).filter(fieldName =>
328
- !fieldName.startsWith('@') &&
329
- !DISPLAY_FIELDS.includes(fieldName) &&
330
- log[fieldName] !== null &&
331
- log[fieldName] !== undefined
332
- ).sort();
333
-
334
- fieldsToDisplay = [...atFields, ...displayFields, ...otherFields];
335
- }
336
- } else {
337
- fieldsToDisplay = columnFilter || Object.keys(log).filter(k => !k.startsWith('@'));
338
- }
339
-
340
- fieldsToDisplay.forEach(fieldName => {
341
- if (!log.hasOwnProperty(fieldName)) return;
342
- if (!raw && isBlacklisted(fieldName)) return;
343
- if (log[fieldName] === null || log[fieldName] === undefined) return;
344
-
345
- const color = getFieldColor(fieldName, isTTY);
346
- const value = applyHighlightAndTruncate(log[fieldName], fieldName, truncate, keyword, highlight);
347
- const highlightedKey = highlightFieldName(fieldName, keyword && highlight ? keyword : [], color);
348
-
349
- console.log(`${highlightedKey}=${value}${RESET}`);
350
- });
351
-
352
- console.log('\x1b[90m' + '='.repeat(80) + '\x1b[0m');
353
- } else {
354
- formatLogEntry(log, raw, logFormat, columns, truncate, keyword, highlight);
355
- }
356
-
357
- previousGroupValues = currentGroupValues;
358
- });
359
- }
360
-
361
- module.exports = {
362
- highlightKeyword,
363
- highlightFieldName,
364
- truncateValue,
365
- applyHighlightAndTruncate,
366
- getFieldColor,
367
- formatLogEntry,
368
- displayLogsWithContext,
369
- displayLogs,
370
- };