@stainlessdev/xray-core 0.4.0 → 0.5.0

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/dist/index.cjs CHANGED
@@ -159,11 +159,9 @@ var defaultRoute = {
159
159
  normalize: true,
160
160
  normalizer: normalizeRoutePattern
161
161
  };
162
- var DEFAULT_ENDPOINT_URL = "http://localhost:4318";
163
162
  var defaultExporterBase = {
164
- endpointUrl: DEFAULT_ENDPOINT_URL,
165
163
  headers: {},
166
- timeoutMs: 5e3,
164
+ timeoutMs: 3e4,
167
165
  spanProcessor: "batch"
168
166
  };
169
167
  var XrayConfigError = class extends Error {
@@ -258,7 +256,6 @@ function normalizeExporter(endpointUrl, cfg) {
258
256
  const rawHeaders = cfg?.headers ?? defaultExporterBase.headers ?? {};
259
257
  const parsed = applyEndpointAuth(resolvedEndpoint, rawHeaders);
260
258
  const exporter = {
261
- ...defaultExporterBase,
262
259
  endpointUrl: parsed.endpointUrl,
263
260
  headers: parsed.headers,
264
261
  timeoutMs: cfg?.timeoutMs ?? defaultExporterBase.timeoutMs,
@@ -268,7 +265,13 @@ function normalizeExporter(endpointUrl, cfg) {
268
265
  }
269
266
  function normalizeExporterEndpoint(endpointUrl) {
270
267
  const envUrl = typeof process !== "undefined" ? process.env?.["STAINLESS_XRAY_ENDPOINT_URL"] : void 0;
271
- const resolved = endpointUrl ?? envUrl ?? DEFAULT_ENDPOINT_URL;
268
+ const resolved = endpointUrl ?? envUrl;
269
+ if (!resolved || !resolved.trim()) {
270
+ throw new XrayConfigError(
271
+ "INVALID_CONFIG",
272
+ "endpointUrl is required (set endpointUrl or STAINLESS_XRAY_ENDPOINT_URL)"
273
+ );
274
+ }
272
275
  const trimmed = resolved.trim();
273
276
  const withoutTrailingSlash = trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
274
277
  if (withoutTrailingSlash.endsWith("/v1/traces")) {
@@ -738,6 +741,9 @@ function sanitizeHeaderValues(headers) {
738
741
  return sanitized;
739
742
  }
740
743
 
744
+ // src/attributes.ts
745
+ var import_incubating = require("@opentelemetry/semantic-conventions/incubating");
746
+
741
747
  // src/attrkey.ts
742
748
  var AttributeKeyRequestBody = "http.request.body";
743
749
  var AttributeKeyRequestBodyEncoding = "http.request.body.encoding";
@@ -749,14 +755,6 @@ var AttributeKeyResponseBodyTruncated = "http.response.body.truncated";
749
755
  var AttributeKeySpanDrop = "stainlessxray.internal.drop";
750
756
 
751
757
  // src/attributes.ts
752
- var attributeKeyEndUserId = "enduser.id";
753
- var attributeKeyHttpRequestBodySize = "http.request.body.size";
754
- var attributeKeyHttpRequestMethod = "http.request.method";
755
- var attributeKeyHttpResponseBodySize = "http.response.body.size";
756
- var attributeKeyHttpResponseStatusCode = "http.response.status_code";
757
- var attributeKeyHttpRoute = "http.route";
758
- var attributeKeyUrlPath = "url.path";
759
- var attributeKeyUrlFull = "url.full";
760
758
  function setHeaderAttributes(span, headers, prefix) {
761
759
  if (!headers) {
762
760
  return;
@@ -771,12 +769,12 @@ function setHeaderAttributes(span, headers, prefix) {
771
769
  }
772
770
  }
773
771
  function setRequestAttributes(span, method, urlFull) {
774
- span.setAttribute(attributeKeyHttpRequestMethod, method);
772
+ span.setAttribute(import_incubating.ATTR_HTTP_REQUEST_METHOD, method);
775
773
  if (urlFull) {
776
- span.setAttribute(attributeKeyUrlFull, urlFull);
774
+ span.setAttribute(import_incubating.ATTR_URL_FULL, urlFull);
777
775
  const path = extractPath(urlFull);
778
776
  if (path) {
779
- span.setAttribute(attributeKeyUrlPath, path);
777
+ span.setAttribute(import_incubating.ATTR_URL_PATH, path);
780
778
  }
781
779
  }
782
780
  }
@@ -799,7 +797,7 @@ function setRequestBodyAttributes(span, body) {
799
797
  }
800
798
  }
801
799
  function setRequestBodySizeAttribute(span, size) {
802
- span.setAttribute(attributeKeyHttpRequestBodySize, size);
800
+ span.setAttribute(import_incubating.ATTR_HTTP_REQUEST_BODY_SIZE, size);
803
801
  }
804
802
  function setResponseBodyAttributes(span, body) {
805
803
  if (!body.value) {
@@ -812,18 +810,18 @@ function setResponseBodyAttributes(span, body) {
812
810
  }
813
811
  }
814
812
  function setResponseBodySizeAttribute(span, size) {
815
- span.setAttribute(attributeKeyHttpResponseBodySize, size);
813
+ span.setAttribute(import_incubating.ATTR_HTTP_RESPONSE_BODY_SIZE, size);
816
814
  }
817
815
  function setResponseStatusAttribute(span, statusCode) {
818
- span.setAttribute(attributeKeyHttpResponseStatusCode, statusCode);
816
+ span.setAttribute(import_incubating.ATTR_HTTP_RESPONSE_STATUS_CODE, statusCode);
819
817
  }
820
818
  function setRouteAttribute(span, route) {
821
819
  if (route) {
822
- span.setAttribute(attributeKeyHttpRoute, route);
820
+ span.setAttribute(import_incubating.ATTR_HTTP_ROUTE, route);
823
821
  }
824
822
  }
825
823
  function setUserIdAttribute(span, userId) {
826
- span.setAttribute(attributeKeyEndUserId, userId);
824
+ span.setAttribute(import_incubating.ATTR_USER_ID, userId);
827
825
  }
828
826
  function setRequestIdAttribute(span, requestId) {
829
827
  span.setAttribute(AttributeKeyRequestID, requestId);
@@ -831,13 +829,11 @@ function setRequestIdAttribute(span, requestId) {
831
829
 
832
830
  // src/otel.ts
833
831
  var import_api = require("@opentelemetry/api");
834
- var import_core = require("@opentelemetry/core");
835
832
  var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
836
833
  var import_resources = require("@opentelemetry/resources");
837
834
  var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
838
- var import_otlp_transformer = require("@opentelemetry/otlp-transformer");
839
835
  var defaultAttributeCountLimit = 128;
840
- function createTracerProvider(config) {
836
+ function createTracerProvider(config, exporter) {
841
837
  if (config.exporter.endpointUrl.startsWith("http://")) {
842
838
  import_api.diag.warn("xray: OTLP endpoint uses plaintext HTTP");
843
839
  }
@@ -848,13 +844,6 @@ function createTracerProvider(config) {
848
844
  [import_semantic_conventions.ATTR_TELEMETRY_SDK_NAME]: "stainless-xray",
849
845
  [import_semantic_conventions.ATTR_TELEMETRY_SDK_VERSION]: sdkVersion()
850
846
  });
851
- const exporter = new FetchSpanExporter({
852
- endpointUrl: config.exporter.endpointUrl,
853
- headers: config.exporter.headers ?? {},
854
- timeoutMillis: config.exporter.timeoutMs,
855
- logger: config.logger,
856
- logLevel: config.logLevel
857
- });
858
847
  const spanProcessor = createSpanProcessor(config.exporter.spanProcessor, exporter);
859
848
  const dropProcessor = new DropFilterSpanProcessor(spanProcessor);
860
849
  const provider = new import_sdk_trace_base.BasicTracerProvider({
@@ -913,77 +902,6 @@ var DropFilterSpanProcessor = class {
913
902
  return this.next.shutdown();
914
903
  }
915
904
  };
916
- var FetchSpanExporter = class {
917
- constructor(options) {
918
- this.endpointUrl = options.endpointUrl;
919
- this.headers = { ...options.headers };
920
- this.timeoutMillis = options.timeoutMillis;
921
- this.isShutdown = false;
922
- this.logger = options.logger;
923
- this.logLevel = options.logLevel;
924
- const protobufSerializer = import_otlp_transformer.ProtobufTraceSerializer && typeof import_otlp_transformer.ProtobufTraceSerializer.serializeRequest === "function" ? import_otlp_transformer.ProtobufTraceSerializer : null;
925
- this.serializer = protobufSerializer ?? import_otlp_transformer.JsonTraceSerializer;
926
- this.contentType = protobufSerializer ? "application/x-protobuf" : "application/json";
927
- }
928
- export(spans, resultCallback) {
929
- if (this.isShutdown) {
930
- resultCallback({ code: import_core.ExportResultCode.FAILED });
931
- return;
932
- }
933
- const payload = this.serializer.serializeRequest(spans);
934
- if (!payload) {
935
- logWithLevel(this.logger, "warn", this.logLevel, "xray: OTLP export failed", {
936
- error: "OTLP export failed: empty payload"
937
- });
938
- resultCallback({
939
- code: import_core.ExportResultCode.FAILED,
940
- error: new Error("OTLP export failed: empty payload")
941
- });
942
- return;
943
- }
944
- const headers = {
945
- ...this.headers,
946
- "Content-Type": this.contentType
947
- };
948
- const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
949
- let timeout;
950
- if (controller) {
951
- timeout = setTimeout(() => controller.abort(), this.timeoutMillis);
952
- }
953
- const doExport = async () => {
954
- const response = await fetch(this.endpointUrl, {
955
- method: "POST",
956
- headers,
957
- body: payload,
958
- signal: controller?.signal
959
- });
960
- if (!response.ok) {
961
- throw new Error(`OTLP export failed: ${response.status}`);
962
- }
963
- };
964
- doExport().then(() => {
965
- if (timeout) {
966
- clearTimeout(timeout);
967
- }
968
- resultCallback({ code: import_core.ExportResultCode.SUCCESS });
969
- }).catch((err) => {
970
- if (timeout) {
971
- clearTimeout(timeout);
972
- }
973
- logWithLevel(this.logger, "warn", this.logLevel, "xray: OTLP export failed", {
974
- error: err instanceof Error ? err.message : String(err)
975
- });
976
- import_api.diag.error("OTLP export failed", err);
977
- resultCallback({ code: import_core.ExportResultCode.FAILED, error: err });
978
- });
979
- }
980
- async forceFlush() {
981
- return;
982
- }
983
- async shutdown() {
984
- this.isShutdown = true;
985
- }
986
- };
987
905
  function createSpanProcessor(mode, exporter) {
988
906
  if (mode === "simple") {
989
907
  return new import_sdk_trace_base.SimpleSpanProcessor(exporter);
@@ -997,7 +915,7 @@ function createSpanProcessor(mode, exporter) {
997
915
  }
998
916
  function sdkVersion() {
999
917
  if (true) {
1000
- return "0.3.1";
918
+ return "0.4.0";
1001
919
  }
1002
920
  return "unknown";
1003
921
  }
@@ -1035,8 +953,14 @@ function getContextState(ctx) {
1035
953
  }
1036
954
 
1037
955
  // src/emitter.ts
1038
- function createEmitter(config) {
956
+ function createEmitter(config, exporter) {
1039
957
  const resolved = normalizeConfig(config);
958
+ if (!exporter) {
959
+ throw new XrayConfigError(
960
+ "INVALID_CONFIG",
961
+ "exporter is required (use @stainlessdev/xray-node or @stainlessdev/xray-fetch)"
962
+ );
963
+ }
1040
964
  logWithLevel(resolved.logger, "info", resolved.logLevel, "xray: emitter configured", {
1041
965
  serviceName: resolved.serviceName,
1042
966
  environment: resolved.environment,
@@ -1044,7 +968,7 @@ function createEmitter(config) {
1044
968
  exporterEndpoint: resolved.exporter.endpointUrl,
1045
969
  spanProcessor: resolved.exporter.spanProcessor
1046
970
  });
1047
- const tracerProvider = createTracerProvider(resolved);
971
+ const tracerProvider = createTracerProvider(resolved, exporter);
1048
972
  const tracer = tracerFromProvider(tracerProvider);
1049
973
  return {
1050
974
  config: resolved,