autotel-devtools 5.0.0 → 5.1.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/cli.js CHANGED
@@ -4,6 +4,7 @@ import { readFileSync, existsSync } from 'fs';
4
4
  import { dirname, resolve } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { WebSocketServer, WebSocket } from 'ws';
7
+ import protobuf from 'protobufjs';
7
8
 
8
9
  // src/server/error-aggregator.ts
9
10
  var ErrorAggregator = class {
@@ -525,7 +526,7 @@ var SPAN_KIND_MAP = {
525
526
  function normalizeHexId(id) {
526
527
  if (!id) return "";
527
528
  const isBase64Like = /^[A-Za-z0-9+/=]+$/.test(id) && !/^[0-9a-f]+$/i.test(id);
528
- const isLikelyBase64Id = isBase64Like && (id.length === 24 || id.length === 28 || id.length === 44 || id.length === 48);
529
+ const isLikelyBase64Id = isBase64Like && (id.length === 12 || id.length === 24 || id.length === 28 || id.length === 44 || id.length === 48);
529
530
  if (isLikelyBase64Id) {
530
531
  try {
531
532
  const bytes = Buffer.from(id, "base64");
@@ -657,13 +658,255 @@ async function readJsonBody(req) {
657
658
  req.on("error", reject);
658
659
  });
659
660
  }
661
+ async function readRawBody(req) {
662
+ return new Promise((resolve3, reject) => {
663
+ const chunks = [];
664
+ req.on("data", (chunk) => chunks.push(chunk));
665
+ req.on("end", () => resolve3(Buffer.concat(chunks)));
666
+ req.on("error", reject);
667
+ });
668
+ }
669
+ function isProtobufContentType(contentType) {
670
+ if (!contentType) return false;
671
+ const value = contentType.toLowerCase();
672
+ return value.includes("application/x-protobuf") || value.includes("application/protobuf");
673
+ }
660
674
  function sendJson(res, status, data) {
661
675
  const body = JSON.stringify(data);
662
676
  res.writeHead(status, { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(body) });
663
677
  res.end(body);
664
678
  }
679
+ var COMMON_PROTO = `
680
+ syntax = "proto3";
681
+ package opentelemetry.proto.common.v1;
682
+
683
+ message AnyValue {
684
+ oneof value {
685
+ string string_value = 1;
686
+ bool bool_value = 2;
687
+ int64 int_value = 3;
688
+ double double_value = 4;
689
+ ArrayValue array_value = 5;
690
+ KeyValueList kvlist_value = 6;
691
+ bytes bytes_value = 7;
692
+ }
693
+ }
694
+ message ArrayValue { repeated AnyValue values = 1; }
695
+ message KeyValueList { repeated KeyValue values = 1; }
696
+ message KeyValue {
697
+ string key = 1;
698
+ AnyValue value = 2;
699
+ }
700
+ message InstrumentationScope {
701
+ string name = 1;
702
+ string version = 2;
703
+ repeated KeyValue attributes = 3;
704
+ uint32 dropped_attributes_count = 4;
705
+ }
706
+ `;
707
+ var RESOURCE_PROTO = `
708
+ syntax = "proto3";
709
+ package opentelemetry.proto.resource.v1;
710
+
711
+ message Resource {
712
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 1;
713
+ uint32 dropped_attributes_count = 2;
714
+ }
715
+ `;
716
+ var TRACE_PROTO = `
717
+ syntax = "proto3";
718
+ package opentelemetry.proto.trace.v1;
719
+
720
+ message ResourceSpans {
721
+ opentelemetry.proto.resource.v1.Resource resource = 1;
722
+ repeated ScopeSpans scope_spans = 2;
723
+ string schema_url = 3;
724
+ }
725
+ message ScopeSpans {
726
+ opentelemetry.proto.common.v1.InstrumentationScope scope = 1;
727
+ repeated Span spans = 2;
728
+ string schema_url = 3;
729
+ }
730
+ message Span {
731
+ bytes trace_id = 1;
732
+ bytes span_id = 2;
733
+ string trace_state = 3;
734
+ bytes parent_span_id = 4;
735
+ fixed32 flags = 16;
736
+ string name = 5;
737
+ SpanKind kind = 6;
738
+ fixed64 start_time_unix_nano = 7;
739
+ fixed64 end_time_unix_nano = 8;
740
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 9;
741
+ uint32 dropped_attributes_count = 10;
742
+ repeated Event events = 11;
743
+ uint32 dropped_events_count = 12;
744
+ repeated Link links = 13;
745
+ uint32 dropped_links_count = 14;
746
+ Status status = 15;
747
+
748
+ enum SpanKind {
749
+ SPAN_KIND_UNSPECIFIED = 0;
750
+ SPAN_KIND_INTERNAL = 1;
751
+ SPAN_KIND_SERVER = 2;
752
+ SPAN_KIND_CLIENT = 3;
753
+ SPAN_KIND_PRODUCER = 4;
754
+ SPAN_KIND_CONSUMER = 5;
755
+ }
756
+ message Event {
757
+ fixed64 time_unix_nano = 1;
758
+ string name = 2;
759
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 3;
760
+ uint32 dropped_attributes_count = 4;
761
+ }
762
+ message Link {
763
+ bytes trace_id = 1;
764
+ bytes span_id = 2;
765
+ string trace_state = 3;
766
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 4;
767
+ uint32 dropped_attributes_count = 5;
768
+ fixed32 flags = 6;
769
+ }
770
+ }
771
+ message Status {
772
+ reserved 1;
773
+ string message = 2;
774
+ StatusCode code = 3;
775
+
776
+ enum StatusCode {
777
+ STATUS_CODE_UNSET = 0;
778
+ STATUS_CODE_OK = 1;
779
+ STATUS_CODE_ERROR = 2;
780
+ }
781
+ }
782
+ message ExportTraceServiceRequest {
783
+ repeated ResourceSpans resource_spans = 1;
784
+ }
785
+ `;
786
+ var LOGS_PROTO = `
787
+ syntax = "proto3";
788
+ package opentelemetry.proto.logs.v1;
789
+
790
+ enum SeverityNumber {
791
+ SEVERITY_NUMBER_UNSPECIFIED = 0;
792
+ SEVERITY_NUMBER_TRACE = 1;
793
+ SEVERITY_NUMBER_TRACE2 = 2;
794
+ SEVERITY_NUMBER_TRACE3 = 3;
795
+ SEVERITY_NUMBER_TRACE4 = 4;
796
+ SEVERITY_NUMBER_DEBUG = 5;
797
+ SEVERITY_NUMBER_DEBUG2 = 6;
798
+ SEVERITY_NUMBER_DEBUG3 = 7;
799
+ SEVERITY_NUMBER_DEBUG4 = 8;
800
+ SEVERITY_NUMBER_INFO = 9;
801
+ SEVERITY_NUMBER_INFO2 = 10;
802
+ SEVERITY_NUMBER_INFO3 = 11;
803
+ SEVERITY_NUMBER_INFO4 = 12;
804
+ SEVERITY_NUMBER_WARN = 13;
805
+ SEVERITY_NUMBER_WARN2 = 14;
806
+ SEVERITY_NUMBER_WARN3 = 15;
807
+ SEVERITY_NUMBER_WARN4 = 16;
808
+ SEVERITY_NUMBER_ERROR = 17;
809
+ SEVERITY_NUMBER_ERROR2 = 18;
810
+ SEVERITY_NUMBER_ERROR3 = 19;
811
+ SEVERITY_NUMBER_ERROR4 = 20;
812
+ SEVERITY_NUMBER_FATAL = 21;
813
+ SEVERITY_NUMBER_FATAL2 = 22;
814
+ SEVERITY_NUMBER_FATAL3 = 23;
815
+ SEVERITY_NUMBER_FATAL4 = 24;
816
+ }
817
+ message ResourceLogs {
818
+ opentelemetry.proto.resource.v1.Resource resource = 1;
819
+ repeated ScopeLogs scope_logs = 2;
820
+ string schema_url = 3;
821
+ }
822
+ message ScopeLogs {
823
+ opentelemetry.proto.common.v1.InstrumentationScope scope = 1;
824
+ repeated LogRecord log_records = 2;
825
+ string schema_url = 3;
826
+ }
827
+ message LogRecord {
828
+ reserved 4;
829
+ fixed64 time_unix_nano = 1;
830
+ fixed64 observed_time_unix_nano = 11;
831
+ SeverityNumber severity_number = 2;
832
+ string severity_text = 3;
833
+ opentelemetry.proto.common.v1.AnyValue body = 5;
834
+ repeated opentelemetry.proto.common.v1.KeyValue attributes = 6;
835
+ uint32 dropped_attributes_count = 7;
836
+ fixed32 flags = 8;
837
+ bytes trace_id = 9;
838
+ bytes span_id = 10;
839
+ }
840
+ message ExportLogsServiceRequest {
841
+ repeated ResourceLogs resource_logs = 1;
842
+ }
843
+ `;
844
+ var METRICS_PROTO = `
845
+ syntax = "proto3";
846
+ package opentelemetry.proto.metrics.v1;
847
+
848
+ message ResourceMetrics {
849
+ opentelemetry.proto.resource.v1.Resource resource = 1;
850
+ repeated ScopeMetrics scope_metrics = 2;
851
+ string schema_url = 3;
852
+ }
853
+ message ScopeMetrics {
854
+ opentelemetry.proto.common.v1.InstrumentationScope scope = 1;
855
+ repeated Metric metrics = 2;
856
+ string schema_url = 3;
857
+ }
858
+ message Metric {
859
+ string name = 1;
860
+ string description = 2;
861
+ string unit = 3;
862
+ }
863
+ message ExportMetricsServiceRequest {
864
+ repeated ResourceMetrics resource_metrics = 1;
865
+ }
866
+ `;
867
+ var TO_OBJECT_OPTIONS = {
868
+ longs: String,
869
+ bytes: String,
870
+ defaults: false
871
+ };
872
+ var cachedRoot = null;
873
+ function getRoot() {
874
+ if (cachedRoot) return cachedRoot;
875
+ const root = new protobuf.Root();
876
+ for (const source of [COMMON_PROTO, RESOURCE_PROTO, TRACE_PROTO, LOGS_PROTO, METRICS_PROTO]) {
877
+ protobuf.parse(source, root, { keepCase: false });
878
+ }
879
+ root.resolveAll();
880
+ cachedRoot = root;
881
+ return root;
882
+ }
883
+ function decodeRequest(typeName, body) {
884
+ const messageType = getRoot().lookupType(typeName);
885
+ const message = messageType.decode(body);
886
+ return messageType.toObject(message, TO_OBJECT_OPTIONS);
887
+ }
888
+ function decodeOtlpTraceRequest(body) {
889
+ return decodeRequest("opentelemetry.proto.trace.v1.ExportTraceServiceRequest", body);
890
+ }
891
+ function decodeOtlpLogsRequest(body) {
892
+ return decodeRequest("opentelemetry.proto.logs.v1.ExportLogsServiceRequest", body);
893
+ }
894
+ function decodeOtlpMetricsRequest(body) {
895
+ return decodeRequest("opentelemetry.proto.metrics.v1.ExportMetricsServiceRequest", body);
896
+ }
665
897
 
666
898
  // src/server/http.ts
899
+ var PROTOBUF_DECODERS = {
900
+ traces: decodeOtlpTraceRequest,
901
+ logs: decodeOtlpLogsRequest,
902
+ metrics: decodeOtlpMetricsRequest
903
+ };
904
+ async function readOtlpPayload(req, signal) {
905
+ if (isProtobufContentType(req.headers["content-type"])) {
906
+ return PROTOBUF_DECODERS[signal](await readRawBody(req));
907
+ }
908
+ return readJsonBody(req);
909
+ }
667
910
  function findPackageRoot() {
668
911
  let dir = dirname(fileURLToPath(import.meta.url));
669
912
  for (let i = 0; i < 5; i++) {
@@ -732,33 +975,33 @@ function attachDevtoolsRoutes(httpServer, devtools) {
732
975
  }
733
976
  if (req.method === "POST" && url === "/v1/traces") {
734
977
  try {
735
- const payload = await readJsonBody(req);
978
+ const payload = await readOtlpPayload(req, "traces");
736
979
  const traces = parseOtlpTraces(payload);
737
980
  devtools.addTraces(traces);
738
981
  sendJson(res, 200, { acceptedTraces: traces.length });
739
982
  } catch (e) {
740
- sendJson(res, 400, { error: "Invalid OTLP JSON", message: e instanceof Error ? e.message : String(e) });
983
+ sendJson(res, 400, { error: "Invalid OTLP payload", message: e instanceof Error ? e.message : String(e) });
741
984
  }
742
985
  return;
743
986
  }
744
987
  if (req.method === "POST" && url === "/v1/logs") {
745
988
  try {
746
- const payload = await readJsonBody(req);
989
+ const payload = await readOtlpPayload(req, "logs");
747
990
  const logs = parseOtlpLogs(payload);
748
991
  devtools.addLogs(logs);
749
992
  sendJson(res, 200, { acceptedLogs: logs.length });
750
993
  } catch (e) {
751
- sendJson(res, 400, { error: "Invalid OTLP JSON", message: e instanceof Error ? e.message : String(e) });
994
+ sendJson(res, 400, { error: "Invalid OTLP payload", message: e instanceof Error ? e.message : String(e) });
752
995
  }
753
996
  return;
754
997
  }
755
998
  if (req.method === "POST" && url === "/v1/metrics") {
756
999
  try {
757
- const payload = await readJsonBody(req);
1000
+ const payload = await readOtlpPayload(req, "metrics");
758
1001
  const count = countOtlpMetrics(payload);
759
1002
  sendJson(res, 200, { acceptedMetrics: count });
760
1003
  } catch (e) {
761
- sendJson(res, 400, { error: "Invalid OTLP JSON", message: e instanceof Error ? e.message : String(e) });
1004
+ sendJson(res, 400, { error: "Invalid OTLP payload", message: e instanceof Error ? e.message : String(e) });
762
1005
  }
763
1006
  return;
764
1007
  }