Branch data Line data Source code
1 : : #include <hpactor/net/http_client.hpp>
2 : : #include <hpactor/net/http_types.hpp>
3 : : #include <hpactor/tracing/json_exporter.hpp>
4 : : #include <hpactor/tracing/otlp_exporter.hpp>
5 : : #include <hpactor/tracing/trace_context_parser.hpp>
6 : :
7 : : #include <sstream>
8 : :
9 : : namespace hpactor::tracing {
10 : :
11 : : namespace {
12 : :
13 : 1 : std::string trace_id_hex(const TraceId& id) {
14 : 1 : TraceContext ctx;
15 : 1 : ctx.trace_id = id;
16 : 1 : ctx.span_id.bytes[7] = 1;
17 : 1 : return format_traceparent(ctx).substr(3, 32);
18 : : }
19 : :
20 : 1 : std::string span_id_hex(const SpanId& id) {
21 : 1 : TraceContext ctx;
22 : 1 : ctx.trace_id.bytes[15] = 1;
23 : 1 : ctx.span_id = id;
24 : 1 : return format_traceparent(ctx).substr(36, 16);
25 : : }
26 : :
27 : 1 : int otlp_span_kind(SpanKind kind) {
28 : 1 : switch (kind) {
29 : 0 : case SpanKind::kInternal:
30 : 0 : return 1;
31 : 0 : case SpanKind::kServer:
32 : 0 : return 2;
33 : 0 : case SpanKind::kClient:
34 : 0 : return 3;
35 : 0 : case SpanKind::kProducer:
36 : 0 : return 4;
37 : 1 : case SpanKind::kConsumer:
38 : 1 : return 5;
39 : : }
40 : 0 : return 0;
41 : : }
42 : :
43 : : } // namespace
44 : :
45 : 1 : OtlpHttpExporter::OtlpHttpExporter(std::string endpoint)
46 : 1 : : endpoint_(std::move(endpoint)) {}
47 : :
48 : : std::string
49 : 1 : OtlpHttpExporter::build_json_payload_for_test(std::span<const SpanRecord> batch,
50 : : const std::string& service_name) const {
51 : 1 : std::ostringstream os;
52 : : os << R"({"resourceSpans":[{"resource":{"attributes":[)"
53 : : << R"({"key":"service.name","value":{"stringValue":")" << service_name
54 : 1 : << R"("}}]},"scopeSpans":[{"scope":{"name":"hpactor-native"},"spans":[)";
55 : 2 : for (size_t i = 0; i < batch.size(); ++i) {
56 : 1 : const auto& r = batch[i];
57 : 1 : if (i != 0)
58 : 0 : os << ',';
59 : 2 : os << R"({"traceId":")" << trace_id_hex(r.trace_id) << R"(","spanId":")"
60 : 2 : << span_id_hex(r.span_id) << R"(","name":"hpactor.span")"
61 : 3 : << R"(,"kind":)" << otlp_span_kind(r.kind)
62 : 1 : << R"(,"startTimeUnixNano":")" << r.start_ns << '"'
63 : 1 : << R"(,"endTimeUnixNano":")" << r.end_ns << '"' << R"(,"attributes":[)"
64 : 1 : << R"({"key":"hpactor.actor.id","value":{"intValue":")"
65 : 1 : << r.actor_id.value() << R"("}},)"
66 : 1 : << R"({"key":"hpactor.message.type_tag","value":{"intValue":")"
67 : 1 : << r.type_tag << R"("}}]})";
68 : : }
69 : 1 : os << R"(]}]}]}]})";
70 : 1 : return os.str();
71 : 1 : }
72 : :
73 : : result<void>
74 : 0 : OtlpHttpExporter::export_batch(std::span<const SpanRecord> batch) noexcept {
75 : 0 : if (batch.empty()) {
76 : 0 : return result<void>::make();
77 : : }
78 : 0 : std::string body_text = build_json_payload_for_test(batch, "hpactor");
79 : 0 : StreamBuffer body;
80 : 0 : body.append(reinterpret_cast<const uint8_t*>(body_text.data()),
81 : : body_text.size());
82 : :
83 : 0 : hpactor::net::HttpClient client(nullptr);
84 : : std::vector<hpactor::net::HttpHeader> headers = {
85 : : {"content-type", "application/json"},
86 : 0 : };
87 : : auto response =
88 : 0 : client.post(endpoint_, std::move(body), std::move(headers)).get();
89 : 0 : if (!response.has_value()) {
90 : : return result<void>::make(
91 : 0 : error(response.error().code(), response.error().message()));
92 : : }
93 : 0 : return result<void>::make();
94 : 0 : }
95 : :
96 : : } // namespace hpactor::tracing
|