@unito/integration-sdk 2.3.3 → 2.3.4

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.
@@ -3,6 +3,7 @@
3
3
  var integrationApi = require('@unito/integration-api');
4
4
  var cachette = require('cachette');
5
5
  var crypto = require('crypto');
6
+ var util = require('util');
6
7
  var express = require('express');
7
8
  var busboy = require('busboy');
8
9
  var https = require('https');
@@ -161,7 +162,12 @@ class Logger {
161
162
  status: logLevel,
162
163
  };
163
164
  if (process.env.NODE_ENV === 'development') {
164
- console[logLevel](JSON.stringify(processedLogs, null, 2));
165
+ const coloredMessage = Logger.colorize(message, processedLogs, logLevel);
166
+ const metadata = {
167
+ date: new Date(processedLogs.date).toISOString(),
168
+ ...processedMetadata,
169
+ };
170
+ console[logLevel](`${coloredMessage} ${JSON.stringify(metadata, null, 2)}`);
165
171
  }
166
172
  else {
167
173
  console[logLevel](JSON.stringify(processedLogs));
@@ -204,6 +210,56 @@ class Logger {
204
210
  }
205
211
  return prunedMetadata;
206
212
  }
213
+ /**
214
+ * Colorizes the log message based on the log level and status codes.
215
+ * @param message The message to colorize.
216
+ * @param metadata The metadata associated with the log.
217
+ * @param logLevel The log level of the message.
218
+ * @returns The colorized output string.
219
+ */
220
+ static colorize(message, metadata, logLevel) {
221
+ if (!process.stdout.isTTY) {
222
+ return message;
223
+ }
224
+ const logOutput = `${logLevel}: ${message}`;
225
+ // Extract status code from logs
226
+ let statusCode;
227
+ if (metadata.http && typeof metadata.http === 'object' && !Array.isArray(metadata.http)) {
228
+ const statusCodeValue = metadata.http.status_code;
229
+ if (typeof statusCodeValue === 'number') {
230
+ statusCode = statusCodeValue;
231
+ }
232
+ else if (typeof statusCodeValue === 'string') {
233
+ statusCode = parseInt(statusCodeValue, 10);
234
+ }
235
+ }
236
+ // Color based on status code first
237
+ if (statusCode) {
238
+ if (statusCode >= 400) {
239
+ return util.styleText('red', logOutput);
240
+ }
241
+ else if (statusCode >= 300) {
242
+ return util.styleText('yellow', logOutput);
243
+ }
244
+ else if (statusCode >= 200) {
245
+ return util.styleText('green', logOutput);
246
+ }
247
+ }
248
+ // Fall back to log level if no status code found
249
+ switch (logLevel) {
250
+ case LogLevel.ERROR:
251
+ return util.styleText('red', logOutput);
252
+ case LogLevel.WARN:
253
+ return util.styleText('yellow', logOutput);
254
+ case LogLevel.INFO:
255
+ case LogLevel.LOG:
256
+ return util.styleText('green', logOutput);
257
+ case LogLevel.DEBUG:
258
+ return util.styleText('cyan', logOutput);
259
+ default:
260
+ return logOutput;
261
+ }
262
+ }
207
263
  }
208
264
  const NULL_LOGGER = new Logger({}, true);
209
265
 
@@ -68,6 +68,14 @@ export default class Logger {
68
68
  private send;
69
69
  private static snakifyKeys;
70
70
  private static pruneSensitiveMetadata;
71
+ /**
72
+ * Colorizes the log message based on the log level and status codes.
73
+ * @param message The message to colorize.
74
+ * @param metadata The metadata associated with the log.
75
+ * @param logLevel The log level of the message.
76
+ * @returns The colorized output string.
77
+ */
78
+ private static colorize;
71
79
  }
72
80
  export declare const NULL_LOGGER: Logger;
73
81
  export {};
@@ -1,3 +1,4 @@
1
+ import { styleText } from 'util';
1
2
  var LogLevel;
2
3
  (function (LogLevel) {
3
4
  LogLevel["ERROR"] = "error";
@@ -133,7 +134,12 @@ export default class Logger {
133
134
  status: logLevel,
134
135
  };
135
136
  if (process.env.NODE_ENV === 'development') {
136
- console[logLevel](JSON.stringify(processedLogs, null, 2));
137
+ const coloredMessage = Logger.colorize(message, processedLogs, logLevel);
138
+ const metadata = {
139
+ date: new Date(processedLogs.date).toISOString(),
140
+ ...processedMetadata,
141
+ };
142
+ console[logLevel](`${coloredMessage} ${JSON.stringify(metadata, null, 2)}`);
137
143
  }
138
144
  else {
139
145
  console[logLevel](JSON.stringify(processedLogs));
@@ -176,5 +182,55 @@ export default class Logger {
176
182
  }
177
183
  return prunedMetadata;
178
184
  }
185
+ /**
186
+ * Colorizes the log message based on the log level and status codes.
187
+ * @param message The message to colorize.
188
+ * @param metadata The metadata associated with the log.
189
+ * @param logLevel The log level of the message.
190
+ * @returns The colorized output string.
191
+ */
192
+ static colorize(message, metadata, logLevel) {
193
+ if (!process.stdout.isTTY) {
194
+ return message;
195
+ }
196
+ const logOutput = `${logLevel}: ${message}`;
197
+ // Extract status code from logs
198
+ let statusCode;
199
+ if (metadata.http && typeof metadata.http === 'object' && !Array.isArray(metadata.http)) {
200
+ const statusCodeValue = metadata.http.status_code;
201
+ if (typeof statusCodeValue === 'number') {
202
+ statusCode = statusCodeValue;
203
+ }
204
+ else if (typeof statusCodeValue === 'string') {
205
+ statusCode = parseInt(statusCodeValue, 10);
206
+ }
207
+ }
208
+ // Color based on status code first
209
+ if (statusCode) {
210
+ if (statusCode >= 400) {
211
+ return styleText('red', logOutput);
212
+ }
213
+ else if (statusCode >= 300) {
214
+ return styleText('yellow', logOutput);
215
+ }
216
+ else if (statusCode >= 200) {
217
+ return styleText('green', logOutput);
218
+ }
219
+ }
220
+ // Fall back to log level if no status code found
221
+ switch (logLevel) {
222
+ case LogLevel.ERROR:
223
+ return styleText('red', logOutput);
224
+ case LogLevel.WARN:
225
+ return styleText('yellow', logOutput);
226
+ case LogLevel.INFO:
227
+ case LogLevel.LOG:
228
+ return styleText('green', logOutput);
229
+ case LogLevel.DEBUG:
230
+ return styleText('cyan', logOutput);
231
+ default:
232
+ return logOutput;
233
+ }
234
+ }
179
235
  }
180
236
  export const NULL_LOGGER = new Logger({}, true);
@@ -129,7 +129,7 @@ describe('Logger', () => {
129
129
  { id: 2, organization_id: 'b' },
130
130
  ]);
131
131
  });
132
- it('prunes sensitive Metadata', { only: true }, testContext => {
132
+ it('prunes sensitive Metadata', testContext => {
133
133
  const logSpy = testContext.mock.method(global.console, 'log', () => { });
134
134
  assert.strictEqual(logSpy.mock.calls.length, 0);
135
135
  const metadata = {
@@ -177,4 +177,77 @@ describe('Logger', () => {
177
177
  assert.strictEqual(infoSpy.mock.calls.length, 0);
178
178
  assert.strictEqual(debugSpy.mock.calls.length, 0);
179
179
  });
180
+ it('colorizes logs by status codes over log levels', () => {
181
+ const originalEnv = process.env.NODE_ENV;
182
+ const originalIsTTY = process.stdout.isTTY;
183
+ try {
184
+ process.env.NODE_ENV = 'development';
185
+ Object.defineProperty(process.stdout, 'isTTY', {
186
+ value: true,
187
+ configurable: true,
188
+ });
189
+ // 4xx status with warn level, should be red
190
+ const metadataWith400 = {
191
+ http: { status_code: 400 },
192
+ };
193
+ const redResult = Logger['colorize']('Some error', metadataWith400, 'warn');
194
+ // warn level without status code, should be yellow
195
+ const metadataNoStatus = {};
196
+ const yellowResult = Logger['colorize']('Some warning', metadataNoStatus, 'warn');
197
+ // Results should be different colors
198
+ assert.notEqual(redResult, yellowResult);
199
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
200
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
201
+ }
202
+ finally {
203
+ // Restore original values
204
+ process.env.NODE_ENV = originalEnv;
205
+ Object.defineProperty(process.stdout, 'isTTY', {
206
+ value: originalIsTTY,
207
+ configurable: true,
208
+ });
209
+ }
210
+ });
211
+ it('colorizes logs with different status code ranges', () => {
212
+ const originalEnv = process.env.NODE_ENV;
213
+ const originalIsTTY = process.stdout.isTTY;
214
+ try {
215
+ process.env.NODE_ENV = 'development';
216
+ Object.defineProperty(process.stdout, 'isTTY', {
217
+ value: true,
218
+ configurable: true,
219
+ });
220
+ // 2xx status codes should be green
221
+ const successMetadata = {
222
+ http: { status_code: 200 },
223
+ };
224
+ const greenResult = Logger['colorize']('Success', successMetadata, 'info');
225
+ assert.ok(greenResult.includes('\x1b[32m')); // Green color code
226
+ // 3xx status codes should be yellow
227
+ const redirectMetadata = {
228
+ http: { status_code: 301 },
229
+ };
230
+ const yellowResult = Logger['colorize']('Redirect', redirectMetadata, 'info');
231
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
232
+ // 4xx status codes should be red
233
+ const clientErrorMetadata = {
234
+ http: { status_code: 404 },
235
+ };
236
+ const redResult = Logger['colorize']('Not Found', clientErrorMetadata, 'warn');
237
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
238
+ // 5xx status codes should be red
239
+ const serverErrorMetadata = {
240
+ http: { status_code: 500 },
241
+ };
242
+ const redResult2 = Logger['colorize']('Server Error', serverErrorMetadata, 'error');
243
+ assert.ok(redResult2.includes('\x1b[31m')); // Red color code
244
+ }
245
+ finally {
246
+ process.env.NODE_ENV = originalEnv;
247
+ Object.defineProperty(process.stdout, 'isTTY', {
248
+ value: originalIsTTY,
249
+ configurable: true,
250
+ });
251
+ }
252
+ });
180
253
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unito/integration-sdk",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "description": "Integration SDK",
5
5
  "type": "module",
6
6
  "types": "dist/src/index.d.ts",
@@ -1,3 +1,5 @@
1
+ import { styleText } from 'util';
2
+
1
3
  const enum LogLevel {
2
4
  ERROR = 'error',
3
5
  WARN = 'warn',
@@ -162,7 +164,14 @@ export default class Logger {
162
164
  };
163
165
 
164
166
  if (process.env.NODE_ENV === 'development') {
165
- console[logLevel](JSON.stringify(processedLogs, null, 2));
167
+ const coloredMessage = Logger.colorize(message, processedLogs, logLevel);
168
+
169
+ const metadata = {
170
+ date: new Date(processedLogs.date).toISOString(),
171
+ ...processedMetadata,
172
+ };
173
+
174
+ console[logLevel](`${coloredMessage} ${JSON.stringify(metadata, null, 2)}`);
166
175
  } else {
167
176
  console[logLevel](JSON.stringify(processedLogs));
168
177
  }
@@ -209,6 +218,59 @@ export default class Logger {
209
218
 
210
219
  return prunedMetadata;
211
220
  }
221
+
222
+ /**
223
+ * Colorizes the log message based on the log level and status codes.
224
+ * @param message The message to colorize.
225
+ * @param metadata The metadata associated with the log.
226
+ * @param logLevel The log level of the message.
227
+ * @returns The colorized output string.
228
+ */
229
+ private static colorize(message: string, metadata: Value, logLevel: LogLevel): string {
230
+ if (!process.stdout.isTTY) {
231
+ return message;
232
+ }
233
+
234
+ const logOutput = `${logLevel}: ${message}`;
235
+
236
+ // Extract status code from logs
237
+ let statusCode: number | undefined;
238
+ if (metadata.http && typeof metadata.http === 'object' && !Array.isArray(metadata.http)) {
239
+ const statusCodeValue = metadata.http.status_code;
240
+
241
+ if (typeof statusCodeValue === 'number') {
242
+ statusCode = statusCodeValue;
243
+ } else if (typeof statusCodeValue === 'string') {
244
+ statusCode = parseInt(statusCodeValue, 10);
245
+ }
246
+ }
247
+
248
+ // Color based on status code first
249
+ if (statusCode) {
250
+ if (statusCode >= 400) {
251
+ return styleText('red', logOutput);
252
+ } else if (statusCode >= 300) {
253
+ return styleText('yellow', logOutput);
254
+ } else if (statusCode >= 200) {
255
+ return styleText('green', logOutput);
256
+ }
257
+ }
258
+
259
+ // Fall back to log level if no status code found
260
+ switch (logLevel) {
261
+ case LogLevel.ERROR:
262
+ return styleText('red', logOutput);
263
+ case LogLevel.WARN:
264
+ return styleText('yellow', logOutput);
265
+ case LogLevel.INFO:
266
+ case LogLevel.LOG:
267
+ return styleText('green', logOutput);
268
+ case LogLevel.DEBUG:
269
+ return styleText('cyan', logOutput);
270
+ default:
271
+ return logOutput;
272
+ }
273
+ }
212
274
  }
213
275
 
214
276
  export const NULL_LOGGER = new Logger({}, true);
@@ -155,7 +155,7 @@ describe('Logger', () => {
155
155
  ]);
156
156
  });
157
157
 
158
- it('prunes sensitive Metadata', { only: true }, testContext => {
158
+ it('prunes sensitive Metadata', testContext => {
159
159
  const logSpy = testContext.mock.method(global.console, 'log', () => {});
160
160
  assert.strictEqual(logSpy.mock.calls.length, 0);
161
161
 
@@ -209,4 +209,86 @@ describe('Logger', () => {
209
209
  assert.strictEqual(infoSpy.mock.calls.length, 0);
210
210
  assert.strictEqual(debugSpy.mock.calls.length, 0);
211
211
  });
212
+
213
+ it('colorizes logs by status codes over log levels', () => {
214
+ const originalEnv = process.env.NODE_ENV;
215
+ const originalIsTTY = process.stdout.isTTY;
216
+
217
+ try {
218
+ process.env.NODE_ENV = 'development';
219
+ Object.defineProperty(process.stdout, 'isTTY', {
220
+ value: true,
221
+ configurable: true,
222
+ });
223
+
224
+ // 4xx status with warn level, should be red
225
+ const metadataWith400 = {
226
+ http: { status_code: 400 },
227
+ };
228
+ const redResult = Logger['colorize']('Some error', metadataWith400, 'warn' as any);
229
+
230
+ // warn level without status code, should be yellow
231
+ const metadataNoStatus = {};
232
+ const yellowResult = Logger['colorize']('Some warning', metadataNoStatus, 'warn' as any);
233
+
234
+ // Results should be different colors
235
+ assert.notEqual(redResult, yellowResult);
236
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
237
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
238
+ } finally {
239
+ // Restore original values
240
+ process.env.NODE_ENV = originalEnv;
241
+ Object.defineProperty(process.stdout, 'isTTY', {
242
+ value: originalIsTTY,
243
+ configurable: true,
244
+ });
245
+ }
246
+ });
247
+
248
+ it('colorizes logs with different status code ranges', () => {
249
+ const originalEnv = process.env.NODE_ENV;
250
+ const originalIsTTY = process.stdout.isTTY;
251
+
252
+ try {
253
+ process.env.NODE_ENV = 'development';
254
+ Object.defineProperty(process.stdout, 'isTTY', {
255
+ value: true,
256
+ configurable: true,
257
+ });
258
+
259
+ // 2xx status codes should be green
260
+ const successMetadata = {
261
+ http: { status_code: 200 },
262
+ };
263
+ const greenResult = Logger['colorize']('Success', successMetadata, 'info' as any);
264
+ assert.ok(greenResult.includes('\x1b[32m')); // Green color code
265
+
266
+ // 3xx status codes should be yellow
267
+ const redirectMetadata = {
268
+ http: { status_code: 301 },
269
+ };
270
+ const yellowResult = Logger['colorize']('Redirect', redirectMetadata, 'info' as any);
271
+ assert.ok(yellowResult.includes('\x1b[33m')); // Yellow color code
272
+
273
+ // 4xx status codes should be red
274
+ const clientErrorMetadata = {
275
+ http: { status_code: 404 },
276
+ };
277
+ const redResult = Logger['colorize']('Not Found', clientErrorMetadata, 'warn' as any);
278
+ assert.ok(redResult.includes('\x1b[31m')); // Red color code
279
+
280
+ // 5xx status codes should be red
281
+ const serverErrorMetadata = {
282
+ http: { status_code: 500 },
283
+ };
284
+ const redResult2 = Logger['colorize']('Server Error', serverErrorMetadata, 'error' as any);
285
+ assert.ok(redResult2.includes('\x1b[31m')); // Red color code
286
+ } finally {
287
+ process.env.NODE_ENV = originalEnv;
288
+ Object.defineProperty(process.stdout, 'isTTY', {
289
+ value: originalIsTTY,
290
+ configurable: true,
291
+ });
292
+ }
293
+ });
212
294
  });