autotel-devtools 4.0.0 → 5.0.1
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/README.md +69 -4
- package/dist/cli.cjs +367 -26
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +347 -26
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +341 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +321 -9
- package/dist/index.js.map +1 -1
- package/dist/server/index.cjs +285 -8
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +14 -1
- package/dist/server/index.d.ts +14 -1
- package/dist/server/index.js +262 -9
- package/dist/server/index.js.map +1 -1
- package/dist/widget.global.js +2 -2
- package/package.json +22 -20
- package/skills/autotel-devtools/SKILL.md +9 -5
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 * as 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++) {
|
|
@@ -697,7 +940,7 @@ function getWidgetJs() {
|
|
|
697
940
|
function attachDevtoolsRoutes(httpServer, devtools) {
|
|
698
941
|
httpServer.on("request", async (req, res) => {
|
|
699
942
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
700
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
943
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
701
944
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
702
945
|
if (req.method === "OPTIONS") {
|
|
703
946
|
res.writeHead(204);
|
|
@@ -720,41 +963,99 @@ function attachDevtoolsRoutes(httpServer, devtools) {
|
|
|
720
963
|
sendJson(res, 200, { ok: true, clients: devtools.clientCount });
|
|
721
964
|
return;
|
|
722
965
|
}
|
|
966
|
+
if (req.method === "GET" && url === "/v1/traces") {
|
|
967
|
+
const data = devtools.getCurrentData();
|
|
968
|
+
sendJson(res, 200, { traces: data.traces, count: data.traces.length });
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
if (req.method === "DELETE" && url === "/v1/traces") {
|
|
972
|
+
devtools.clearData();
|
|
973
|
+
sendJson(res, 200, { cleared: true });
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
723
976
|
if (req.method === "POST" && url === "/v1/traces") {
|
|
724
977
|
try {
|
|
725
|
-
const payload = await
|
|
978
|
+
const payload = await readOtlpPayload(req, "traces");
|
|
726
979
|
const traces = parseOtlpTraces(payload);
|
|
727
980
|
devtools.addTraces(traces);
|
|
728
981
|
sendJson(res, 200, { acceptedTraces: traces.length });
|
|
729
982
|
} catch (e) {
|
|
730
|
-
sendJson(res, 400, { error: "Invalid OTLP
|
|
983
|
+
sendJson(res, 400, { error: "Invalid OTLP payload", message: e instanceof Error ? e.message : String(e) });
|
|
731
984
|
}
|
|
732
985
|
return;
|
|
733
986
|
}
|
|
734
987
|
if (req.method === "POST" && url === "/v1/logs") {
|
|
735
988
|
try {
|
|
736
|
-
const payload = await
|
|
989
|
+
const payload = await readOtlpPayload(req, "logs");
|
|
737
990
|
const logs = parseOtlpLogs(payload);
|
|
738
991
|
devtools.addLogs(logs);
|
|
739
992
|
sendJson(res, 200, { acceptedLogs: logs.length });
|
|
740
993
|
} catch (e) {
|
|
741
|
-
sendJson(res, 400, { error: "Invalid OTLP
|
|
994
|
+
sendJson(res, 400, { error: "Invalid OTLP payload", message: e instanceof Error ? e.message : String(e) });
|
|
742
995
|
}
|
|
743
996
|
return;
|
|
744
997
|
}
|
|
745
998
|
if (req.method === "POST" && url === "/v1/metrics") {
|
|
746
999
|
try {
|
|
747
|
-
const payload = await
|
|
1000
|
+
const payload = await readOtlpPayload(req, "metrics");
|
|
748
1001
|
const count = countOtlpMetrics(payload);
|
|
749
1002
|
sendJson(res, 200, { acceptedMetrics: count });
|
|
750
1003
|
} catch (e) {
|
|
751
|
-
sendJson(res, 400, { error: "Invalid OTLP
|
|
1004
|
+
sendJson(res, 400, { error: "Invalid OTLP payload", message: e instanceof Error ? e.message : String(e) });
|
|
752
1005
|
}
|
|
753
1006
|
return;
|
|
754
1007
|
}
|
|
755
1008
|
sendJson(res, 404, { error: "Not found" });
|
|
756
1009
|
});
|
|
757
1010
|
}
|
|
1011
|
+
var LOOPBACK = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
|
|
1012
|
+
function formatAddress(host, port) {
|
|
1013
|
+
return host.includes(":") ? `[${host}]:${port}` : `${host}:${port}`;
|
|
1014
|
+
}
|
|
1015
|
+
function listenLoopbackDualStack(args) {
|
|
1016
|
+
const { primary, port, host, attachSecondary } = args;
|
|
1017
|
+
let sibling;
|
|
1018
|
+
const ready = new Promise(
|
|
1019
|
+
(resolve3) => {
|
|
1020
|
+
const addresses = [];
|
|
1021
|
+
const warnings = [];
|
|
1022
|
+
const primaryHost = host === "localhost" ? "127.0.0.1" : host;
|
|
1023
|
+
primary.listen(port, primaryHost, () => {
|
|
1024
|
+
const addr = primary.address();
|
|
1025
|
+
const resolvedPort = addr && typeof addr === "object" ? addr.port : port;
|
|
1026
|
+
addresses.push(formatAddress(primaryHost, resolvedPort));
|
|
1027
|
+
if (!LOOPBACK.has(host)) {
|
|
1028
|
+
resolve3({ addresses, warnings });
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
const siblingHost = primaryHost === "::1" ? "127.0.0.1" : "::1";
|
|
1032
|
+
const s = createServer();
|
|
1033
|
+
attachSecondary(s);
|
|
1034
|
+
const onError = (e) => {
|
|
1035
|
+
s.close();
|
|
1036
|
+
warnings.push(
|
|
1037
|
+
`could not also bind ${formatAddress(siblingHost, resolvedPort)} (${e.message}); clients using the ${siblingHost === "::1" ? "IPv6" : "IPv4"} form of "localhost" may not connect.`
|
|
1038
|
+
);
|
|
1039
|
+
resolve3({ addresses, warnings });
|
|
1040
|
+
};
|
|
1041
|
+
s.once("error", onError);
|
|
1042
|
+
s.listen(resolvedPort, siblingHost, () => {
|
|
1043
|
+
s.off("error", onError);
|
|
1044
|
+
sibling = s;
|
|
1045
|
+
addresses.push(formatAddress(siblingHost, resolvedPort));
|
|
1046
|
+
resolve3({ addresses, warnings });
|
|
1047
|
+
});
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
);
|
|
1051
|
+
return {
|
|
1052
|
+
ready,
|
|
1053
|
+
closeSibling: () => new Promise((res) => {
|
|
1054
|
+
if (!sibling) return res();
|
|
1055
|
+
sibling.close(() => res());
|
|
1056
|
+
})
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
758
1059
|
|
|
759
1060
|
// src/cli.ts
|
|
760
1061
|
function printHelp() {
|
|
@@ -772,13 +1073,15 @@ Options:
|
|
|
772
1073
|
-v, --version Show version number
|
|
773
1074
|
|
|
774
1075
|
Endpoints:
|
|
775
|
-
GET
|
|
776
|
-
GET
|
|
777
|
-
POST
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1076
|
+
GET / Web devtools UI (fullpage)
|
|
1077
|
+
GET /widget.js Widget bundle (embed in your app)
|
|
1078
|
+
POST /v1/traces Receive OTLP JSON trace data
|
|
1079
|
+
GET /v1/traces Read back received traces (verify ingestion in tests)
|
|
1080
|
+
DELETE /v1/traces Clear captured telemetry (test reset)
|
|
1081
|
+
POST /v1/logs Receive OTLP JSON log data
|
|
1082
|
+
POST /v1/metrics Receive OTLP JSON metric data
|
|
1083
|
+
WS /ws WebSocket stream for real-time updates
|
|
1084
|
+
GET /healthz Health check
|
|
782
1085
|
|
|
783
1086
|
Examples:
|
|
784
1087
|
npx autotel-devtools
|
|
@@ -850,29 +1153,47 @@ async function main() {
|
|
|
850
1153
|
const httpServer = createServer();
|
|
851
1154
|
const wsServer = new DevtoolsServer({ server: httpServer, verbose: true });
|
|
852
1155
|
attachDevtoolsRoutes(httpServer, wsServer);
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
1156
|
+
const listeners = listenLoopbackDualStack({
|
|
1157
|
+
primary: httpServer,
|
|
1158
|
+
port: options.port,
|
|
1159
|
+
host: options.host,
|
|
1160
|
+
attachSecondary: (s) => attachDevtoolsRoutes(s, wsServer)
|
|
1161
|
+
});
|
|
1162
|
+
const { addresses, warnings } = await listeners.ready;
|
|
1163
|
+
const uiBase = `http://${options.host === "localhost" ? "127.0.0.1" : options.host}:${options.port}`;
|
|
1164
|
+
const title = options.title || "autotel-devtools";
|
|
1165
|
+
process.stdout.write(`
|
|
856
1166
|
${title}
|
|
857
1167
|
|
|
858
1168
|
`);
|
|
859
|
-
|
|
1169
|
+
process.stdout.write(` Listening: ${addresses.join(" + ")}
|
|
1170
|
+
`);
|
|
1171
|
+
process.stdout.write(` UI: ${uiBase}
|
|
860
1172
|
`);
|
|
861
|
-
|
|
1173
|
+
process.stdout.write(` Widget: <script src="${uiBase}/widget.js"></script>
|
|
862
1174
|
`);
|
|
863
|
-
|
|
1175
|
+
process.stdout.write(` WebSocket: ${uiBase.replace("http", "ws")}/ws
|
|
864
1176
|
`);
|
|
865
|
-
|
|
1177
|
+
process.stdout.write(` OTLP: ${uiBase}/v1/traces
|
|
866
1178
|
|
|
867
1179
|
`);
|
|
868
|
-
|
|
1180
|
+
process.stdout.write(` Set OTEL_EXPORTER_OTLP_PROTOCOL=http/json
|
|
869
1181
|
`);
|
|
870
|
-
|
|
1182
|
+
process.stdout.write(` Set OTEL_EXPORTER_OTLP_ENDPOINT=${uiBase}
|
|
871
1183
|
|
|
872
1184
|
`);
|
|
873
|
-
}
|
|
1185
|
+
process.stdout.write(` Verify ingestion: curl -s ${uiBase}/v1/traces
|
|
1186
|
+
|
|
1187
|
+
`);
|
|
1188
|
+
for (const w of warnings) {
|
|
1189
|
+
process.stdout.write(` \u26A0 ${w}
|
|
1190
|
+
`);
|
|
1191
|
+
}
|
|
1192
|
+
if (warnings.length > 0) process.stdout.write("\n");
|
|
874
1193
|
const shutdown = () => {
|
|
875
|
-
wsServer.close().
|
|
1194
|
+
Promise.all([wsServer.close(), listeners.closeSibling()]).then(
|
|
1195
|
+
() => process.exit(0)
|
|
1196
|
+
);
|
|
876
1197
|
};
|
|
877
1198
|
process.on("SIGINT", shutdown);
|
|
878
1199
|
process.on("SIGTERM", shutdown);
|