@m1212e/rumble 0.23.9 → 0.23.11

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.
package/out/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as lazy } from "./lazy-C7IyM4M4.mjs";
2
2
  import { t as generateFromSchema } from "./generate-0QFVc3Sg.mjs";
3
- import { GraphQLError, GraphQLSchema, execute as defaultExecute, subscribe as defaultSubscribe } from "graphql";
3
+ import { GraphQLError, GraphQLSchema, execute as defaultExecute, getOperationAST, print, subscribe as defaultSubscribe } from "graphql";
4
4
  import { EnvelopArmorPlugin } from "@escape.tech/graphql-armor";
5
5
  import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";
6
6
  import { SpanStatusCode, trace } from "@opentelemetry/api";
@@ -180,7 +180,7 @@ function mapNullFieldsToUndefined(obj) {
180
180
  }
181
181
  //#endregion
182
182
  //#region package.json
183
- var version = "0.23.9";
183
+ var version = "0.23.11";
184
184
  //#endregion
185
185
  //#region lib/helpers/mergeFilters.ts
186
186
  const EmptyFilter$1 = Symbol.for("drizzle:EmptyFilter");
@@ -1305,31 +1305,81 @@ const sofaOpenAPIWebhookDocs = {
1305
1305
  } }
1306
1306
  };
1307
1307
  //#endregion
1308
+ //#region lib/helpers/errorLogging.ts
1309
+ function hasMessage(error) {
1310
+ return typeof error === "object" && error !== null && "message" in error;
1311
+ }
1312
+ function toLoggedException(error) {
1313
+ if (hasMessage(error)) {
1314
+ const gqlError = error;
1315
+ return {
1316
+ "exception.type": gqlError.constructor?.name ?? gqlError.name ?? "Error",
1317
+ "exception.message": String(gqlError.message),
1318
+ ...gqlError.stack ? { "exception.stacktrace": gqlError.stack } : {},
1319
+ ...gqlError.path ? { path: gqlError.path } : {},
1320
+ ...gqlError.extensions && Object.keys(gqlError.extensions).length > 0 ? { extensions: gqlError.extensions } : {}
1321
+ };
1322
+ }
1323
+ return {
1324
+ "exception.type": "UnknownError",
1325
+ "exception.message": String(error)
1326
+ };
1327
+ }
1328
+ /**
1329
+ * Every erroneous rumble log carries the same `errors` array shape,
1330
+ * whether it originates from a thrown exception (single-element array)
1331
+ * or a GraphQL `ExecutionResult.errors` list (multi-element array).
1332
+ */
1333
+ function errorsLogField(errors) {
1334
+ return { errors: errors.map(toLoggedException) };
1335
+ }
1336
+ function errorLogField(error) {
1337
+ return errorsLogField([error]);
1338
+ }
1339
+ //#endregion
1308
1340
  //#region lib/helpers/tracing.ts
1341
+ const SUBSCRIBE_SPAN_NAME = "graphql.subscribe";
1342
+ function getOperationType(options) {
1343
+ return getOperationAST(options.document, options.operationName)?.operation;
1344
+ }
1345
+ function operationLogFields(operationName, operationType) {
1346
+ return {
1347
+ "graphql.operation.name": operationName,
1348
+ ...operationType ? { "graphql.operation.type": operationType } : {}
1349
+ };
1350
+ }
1351
+ function traceIdLogFields(span) {
1352
+ const { traceId, spanId, traceFlags } = span.spanContext();
1353
+ return {
1354
+ trace_id: traceId,
1355
+ span_id: spanId,
1356
+ trace_flags: traceFlags.toString(16).padStart(2, "0")
1357
+ };
1358
+ }
1309
1359
  function isAsyncIterable(value) {
1310
1360
  return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
1311
1361
  }
1312
- async function* wrapSubscriptionIterator(iterator, log, operationName) {
1362
+ async function* wrapSubscriptionIterator(iterator, log, operationName, operationType) {
1313
1363
  let eventCount = 0;
1314
1364
  try {
1315
1365
  for await (const event of iterator) {
1316
1366
  eventCount++;
1317
1367
  if (event.errors?.length) log.error({
1318
- "graphql.operation.name": operationName,
1319
- eventCount,
1320
- errors: event.errors.map((e) => e.message)
1368
+ ...operationLogFields(operationName, operationType),
1369
+ event_count: eventCount,
1370
+ ...errorsLogField(event.errors)
1321
1371
  }, "graphql subscription event error");
1322
1372
  yield event;
1323
1373
  }
1324
1374
  log.info({
1325
- "graphql.operation.name": operationName,
1326
- eventCount
1375
+ ...operationLogFields(operationName, operationType),
1376
+ event_count: eventCount
1327
1377
  }, "graphql subscription completed");
1328
1378
  } catch (error) {
1329
1379
  log.error({
1330
- "graphql.operation.name": operationName,
1331
- eventCount,
1332
- err: error
1380
+ ...operationLogFields(operationName, operationType),
1381
+ event_count: eventCount,
1382
+ ...errorLogField(error)
1333
1383
  }, "graphql subscription threw");
1334
1384
  throw error;
1335
1385
  }
@@ -1338,32 +1388,28 @@ function buildTracedExecute(executeFn, rumbleInput) {
1338
1388
  return async (options) => {
1339
1389
  let log = rumbleInput.logger?.enabled ? rumbleInput.logger.logger : void 0;
1340
1390
  const operationName = options.operationName ?? "anonymous";
1391
+ const operationType = getOperationType(options);
1341
1392
  const start = Date.now();
1342
- log?.info({ "graphql.operation.name": operationName }, "graphql execute start");
1393
+ log?.info(operationLogFields(operationName, operationType), "graphql execute start");
1343
1394
  const run = async () => {
1344
1395
  const result = await executeFn(options);
1345
1396
  if (result && "errors" in result && result.errors?.length) log?.error({
1346
- "graphql.operation.name": operationName,
1347
- durationMs: Date.now() - start,
1348
- errors: result.errors.map((e) => e.message)
1397
+ ...operationLogFields(operationName, operationType),
1398
+ duration_ms: Date.now() - start,
1399
+ ...errorsLogField(result.errors)
1349
1400
  }, "graphql execute completed with errors");
1350
1401
  else log?.info({
1351
- "graphql.operation.name": operationName,
1352
- durationMs: Date.now() - start
1402
+ ...operationLogFields(operationName, operationType),
1403
+ duration_ms: Date.now() - start
1353
1404
  }, "graphql execute completed");
1354
1405
  return result;
1355
1406
  };
1356
1407
  if (rumbleInput.otel?.enabled) return rumbleInput.otel.tracer.startActiveSpan(SpanNames.EXECUTE, { attributes: {
1357
1408
  [AttributeNames.OPERATION_NAME]: operationName,
1358
- [AttributeNames.SOURCE]: options.document
1409
+ ...operationType ? { [AttributeNames.OPERATION_TYPE]: operationType } : {},
1410
+ "graphql.document": print(options.document)
1359
1411
  } }, async (span) => {
1360
- if (log && rumbleInput.logger?.injectTraceId !== false) {
1361
- const { traceId, spanId } = span.spanContext();
1362
- log = log.child({
1363
- traceId,
1364
- spanId
1365
- });
1366
- }
1412
+ if (log && rumbleInput.logger?.injectTraceId !== false) log = log.child(traceIdLogFields(span));
1367
1413
  try {
1368
1414
  const result = await run();
1369
1415
  if (result && "errors" in result && result.errors?.length) {
@@ -1374,9 +1420,9 @@ function buildTracedExecute(executeFn, rumbleInput) {
1374
1420
  } catch (error) {
1375
1421
  if (error instanceof Error) span.recordException(error);
1376
1422
  log?.error({
1377
- "graphql.operation.name": operationName,
1378
- durationMs: Date.now() - start,
1379
- err: error
1423
+ ...operationLogFields(operationName, operationType),
1424
+ duration_ms: Date.now() - start,
1425
+ ...errorLogField(error)
1380
1426
  }, "graphql execute threw");
1381
1427
  span.setStatus({ code: SpanStatusCode.ERROR });
1382
1428
  throw error;
@@ -1388,9 +1434,9 @@ function buildTracedExecute(executeFn, rumbleInput) {
1388
1434
  return await run();
1389
1435
  } catch (error) {
1390
1436
  log?.error({
1391
- "graphql.operation.name": operationName,
1392
- durationMs: Date.now() - start,
1393
- err: error
1437
+ ...operationLogFields(operationName, operationType),
1438
+ duration_ms: Date.now() - start,
1439
+ ...errorLogField(error)
1394
1440
  }, "graphql execute threw");
1395
1441
  throw error;
1396
1442
  }
@@ -1400,34 +1446,33 @@ function buildTracedSubscribe(subscribeFn, rumbleInput) {
1400
1446
  return async (options) => {
1401
1447
  let log = rumbleInput.logger?.enabled ? rumbleInput.logger.logger : void 0;
1402
1448
  const operationName = options.operationName ?? "anonymous";
1449
+ const operationType = getOperationType(options);
1403
1450
  const start = Date.now();
1404
1451
  const doSubscribe = async () => {
1405
- log?.info({ "graphql.operation.name": operationName }, "graphql subscribe start");
1452
+ log?.info(operationLogFields(operationName, operationType), "graphql subscribe start");
1406
1453
  const result = await subscribeFn(options);
1407
1454
  if (!isAsyncIterable(result)) {
1408
1455
  const execResult = result;
1409
1456
  if (execResult.errors?.length) log?.error({
1410
- "graphql.operation.name": operationName,
1411
- durationMs: Date.now() - start,
1412
- errors: execResult.errors.map((e) => e.message)
1457
+ ...operationLogFields(operationName, operationType),
1458
+ duration_ms: Date.now() - start,
1459
+ ...errorsLogField(execResult.errors)
1413
1460
  }, "graphql subscribe completed with errors");
1414
1461
  return execResult;
1415
1462
  }
1416
1463
  log?.info({
1417
- "graphql.operation.name": operationName,
1418
- durationMs: Date.now() - start
1464
+ ...operationLogFields(operationName, operationType),
1465
+ duration_ms: Date.now() - start
1419
1466
  }, "graphql subscription established");
1420
- if (log) return wrapSubscriptionIterator(result, log, operationName);
1467
+ if (log) return wrapSubscriptionIterator(result, log, operationName, operationType);
1421
1468
  return result;
1422
1469
  };
1423
- if (rumbleInput.otel?.enabled) return rumbleInput.otel.tracer.startActiveSpan("graphql.subscribe", async (span) => {
1424
- if (log && rumbleInput.logger?.injectTraceId !== false) {
1425
- const { traceId, spanId } = span.spanContext();
1426
- log = log.child({
1427
- traceId,
1428
- spanId
1429
- });
1430
- }
1470
+ if (rumbleInput.otel?.enabled) return rumbleInput.otel.tracer.startActiveSpan(SUBSCRIBE_SPAN_NAME, { attributes: {
1471
+ [AttributeNames.OPERATION_NAME]: operationName,
1472
+ ...operationType ? { [AttributeNames.OPERATION_TYPE]: operationType } : {},
1473
+ "graphql.document": print(options.document)
1474
+ } }, async (span) => {
1475
+ if (log && rumbleInput.logger?.injectTraceId !== false) log = log.child(traceIdLogFields(span));
1431
1476
  try {
1432
1477
  const result = await doSubscribe();
1433
1478
  if (!isAsyncIterable(result)) {
@@ -1441,9 +1486,9 @@ function buildTracedSubscribe(subscribeFn, rumbleInput) {
1441
1486
  } catch (error) {
1442
1487
  if (error instanceof Error) span.recordException(error);
1443
1488
  log?.error({
1444
- "graphql.operation.name": operationName,
1445
- durationMs: Date.now() - start,
1446
- err: error
1489
+ ...operationLogFields(operationName, operationType),
1490
+ duration_ms: Date.now() - start,
1491
+ ...errorLogField(error)
1447
1492
  }, "graphql subscribe threw");
1448
1493
  span.setStatus({ code: SpanStatusCode.ERROR });
1449
1494
  throw error;
@@ -1455,9 +1500,9 @@ function buildTracedSubscribe(subscribeFn, rumbleInput) {
1455
1500
  return await doSubscribe();
1456
1501
  } catch (error) {
1457
1502
  log?.error({
1458
- "graphql.operation.name": operationName,
1459
- durationMs: Date.now() - start,
1460
- err: error
1503
+ ...operationLogFields(operationName, operationType),
1504
+ duration_ms: Date.now() - start,
1505
+ ...errorLogField(error)
1461
1506
  }, "graphql subscribe threw");
1462
1507
  throw error;
1463
1508
  }
@@ -1550,7 +1595,7 @@ async function initSearchIfApplicable(input) {
1550
1595
  await input.db.execute(sql`CREATE EXTENSION IF NOT EXISTS pg_trgm;`);
1551
1596
  } catch (error) {
1552
1597
  const msg = "Failed to create pg_trgm extension. Search functionality may not work. Ensure the database user has CREATE privilege or the extension is pre-installed.";
1553
- log ? log.error({ err: error }, msg) : console.error(msg, error);
1598
+ log ? log.error(errorLogField(error), msg) : console.error(msg, error);
1554
1599
  return;
1555
1600
  }
1556
1601
  if (input.search?.threshold) {
@@ -2300,7 +2345,7 @@ var RuntimeFiltersPlugin = class extends BasePlugin {
2300
2345
  } catch (error) {
2301
2346
  this.logger?.error({
2302
2347
  "graphql.field.name": fieldConfig.name,
2303
- err: error
2348
+ ...errorLogField(error)
2304
2349
  }, "runtime filter threw");
2305
2350
  throw error;
2306
2351
  } finally {
@@ -2312,7 +2357,7 @@ var RuntimeFiltersPlugin = class extends BasePlugin {
2312
2357
  } catch (error) {
2313
2358
  this.logger?.error({
2314
2359
  "graphql.field.name": fieldConfig.name,
2315
- err: error
2360
+ ...errorLogField(error)
2316
2361
  }, "runtime filter threw");
2317
2362
  throw error;
2318
2363
  }
@@ -2365,13 +2410,13 @@ const createSchemaBuilder = ({ db, pubsub, pothosConfig, otel, logger }) => {
2365
2410
  if (error) log.error({
2366
2411
  "graphql.field.name": config.name,
2367
2412
  "graphql.parent.type": config.parentType,
2368
- durationMs: duration,
2369
- err: error
2413
+ duration_ms: duration,
2414
+ ...errorLogField(error)
2370
2415
  }, "resolver failed");
2371
2416
  else log.debug({
2372
2417
  "graphql.field.name": config.name,
2373
2418
  "graphql.parent.type": config.parentType,
2374
- durationMs: duration
2419
+ duration_ms: duration
2375
2420
  }, "resolver completed");
2376
2421
  });
2377
2422
  }