// Copyright Epic Games, Inc. All Rights Reserved. #include "otlphttp.h" #include #include #include #include #include #include #include #include #if ZEN_WITH_OTEL namespace zen::logging { ////////////////////////////////////////////////////////////////////////// // // Important note: in general we cannot use ZEN_WARN/ZEN_ERROR etc in this // file as it could cause recursive logging calls when we attempt to log // errors from the OTLP HTTP client itself. // OtelHttpProtobufSink::OtelHttpProtobufSink(const std::string_view& Uri) : m_OtelHttp(Uri) { m_Encoder.AddResourceAttribute("service.name", "zenserver"); m_Encoder.AddResourceAttribute("service.instance.id", GetSessionIdString()); m_Encoder.AddResourceAttribute("service.namespace", "zen"); m_Encoder.AddResourceAttribute("service.version", ZEN_CFG_VERSION); m_Encoder.AddResourceAttribute("host.name", GetMachineName()); m_Encoder.AddResourceAttribute("session.id", GetSessionIdString()); m_Encoder.AddResourceAttribute("process.id", zen::GetCurrentProcessId()); m_TraceRecorder = new TraceRecorder(this); otel::SetTraceRecorder(m_TraceRecorder); } OtelHttpProtobufSink::~OtelHttpProtobufSink() { otel::SetTraceRecorder({}); } void OtelHttpProtobufSink::CheckPostResult(const HttpClient::Response& Result, const char* Endpoint) noexcept { if (!Result.IsSuccess()) { uint32_t PrevFailures = m_ConsecutivePostFailures.fetch_add(1); if (PrevFailures < kMaxReportedFailures) { fprintf(stderr, "OtelHttpProtobufSink: %s\n", Result.ErrorMessage(Endpoint).c_str()); if (PrevFailures + 1 == kMaxReportedFailures) { fprintf(stderr, "OtelHttpProtobufSink: suppressing further export errors\n"); } } } else { m_ConsecutivePostFailures.store(0); } } void OtelHttpProtobufSink::RecordSpans(zen::otel::TraceId Trace, std::span Spans) { try { std::string Data = m_Encoder.FormatOtelTrace(Trace, Spans); IoBuffer Payload{IoBuffer::Wrap, Data.data(), Data.size()}; Payload.SetContentType(ZenContentType::kProtobuf); HttpClient::Response Result = m_OtelHttp.Post("/v1/traces", Payload); CheckPostResult(Result, "POST /v1/traces"); } catch (const std::exception& Ex) { fprintf(stderr, "OtelHttpProtobufSink: exception exporting traces: %s\n", Ex.what()); } } void OtelHttpProtobufSink::TraceRecorder::RecordSpans(zen::otel::TraceId Trace, std::span Spans) { m_Sink->RecordSpans(Trace, Spans); } void OtelHttpProtobufSink::Log(const LogMessage& Msg) { try { std::string Data = m_Encoder.FormatOtelProtobuf(Msg); IoBuffer Payload{IoBuffer::Wrap, Data.data(), Data.size()}; Payload.SetContentType(ZenContentType::kProtobuf); HttpClient::Response Result = m_OtelHttp.Post("/v1/logs", Payload); CheckPostResult(Result, "POST /v1/logs"); } catch (const std::exception& Ex) { fprintf(stderr, "OtelHttpProtobufSink: exception exporting logs: %s\n", Ex.what()); } } void OtelHttpProtobufSink::Flush() { } } // namespace zen::logging #endif