amoeba commented on code in PR #39905:
URL: https://github.com/apache/arrow/pull/39905#discussion_r1546791544


##########
cpp/src/arrow/telemetry/logging.cc:
##########
@@ -0,0 +1,336 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/telemetry/logging.h"
+#include "arrow/telemetry/util_internal.h"
+#include "arrow/util/io_util.h"
+#include "arrow/util/logging.h"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522)
+#endif
+
+#include <google/protobuf/util/json_util.h>
+
+#include <opentelemetry/exporters/ostream/log_record_exporter.h>
+#include <opentelemetry/exporters/otlp/otlp_http_log_record_exporter.h>
+#include <opentelemetry/exporters/otlp/otlp_http_log_record_exporter_options.h>
+#include <opentelemetry/exporters/otlp/otlp_recordable_utils.h>
+#include <opentelemetry/logs/logger.h>
+#include <opentelemetry/logs/noop.h>
+#include <opentelemetry/logs/provider.h>
+#include <opentelemetry/sdk/logs/batch_log_record_processor.h>
+#include <opentelemetry/sdk/logs/batch_log_record_processor_options.h>
+#include <opentelemetry/sdk/logs/exporter.h>
+#include <opentelemetry/sdk/logs/logger_provider.h>
+#include <opentelemetry/sdk/resource/resource.h>
+#include <opentelemetry/sdk/resource/resource_detector.h>
+#include <opentelemetry/sdk/resource/semantic_conventions.h>
+#include <opentelemetry/trace/tracer.h>
+
+#include <opentelemetry/exporters/otlp/protobuf_include_prefix.h>
+
+#include <opentelemetry/proto/collector/logs/v1/logs_service.pb.h>
+
+#include <opentelemetry/exporters/otlp/protobuf_include_suffix.h>
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+namespace arrow {
+namespace telemetry {
+
+namespace {
+
+namespace SemanticConventions = otel::sdk::resource::SemanticConventions;
+
+constexpr const char kLoggingBackendEnvVar[] = "ARROW_LOGGING_BACKEND";
+
+class OtlpOStreamLogRecordExporter final : public 
otel::sdk::logs::LogRecordExporter {
+ public:
+  explicit OtlpOStreamLogRecordExporter(std::ostream* sink) : sink_(sink) {
+    pb_json_options_.add_whitespace = false;
+  }
+
+  otel::sdk::common::ExportResult Export(
+      const otel_span<std::unique_ptr<otel::sdk::logs::Recordable>>& records) 
noexcept
+      override {
+    otel::proto::collector::logs::v1::ExportLogsServiceRequest request;
+    otel::exporter::otlp::OtlpRecordableUtils::PopulateRequest(records, 
&request);
+
+    for (const auto& logs : request.resource_logs()) {
+      std::string out;
+      auto status =
+          google::protobuf::util::MessageToJsonString(logs, &out, 
pb_json_options_);
+      if (ARROW_PREDICT_FALSE(!status.ok())) {
+        return otel::sdk::common::ExportResult::kFailure;
+      }
+      (*sink_) << out << std::endl;
+    }
+
+    return otel::sdk::common::ExportResult::kSuccess;
+  }
+
+  bool ForceFlush(std::chrono::microseconds timeout) noexcept override {
+    return exporter_.ForceFlush(timeout);
+  }
+
+  bool Shutdown(std::chrono::microseconds timeout) noexcept override {
+    return exporter_.Shutdown(timeout);
+  }
+
+  std::unique_ptr<otel::sdk::logs::Recordable> MakeRecordable() noexcept 
override {
+    return exporter_.MakeRecordable();
+  }
+
+ private:
+  std::ostream* sink_;
+  otel::exporter::otlp::OtlpHttpLogRecordExporter exporter_;
+  google::protobuf::util::JsonPrintOptions pb_json_options_;
+};
+
+otel::logs::Severity ToOtelSeverity(LogLevel level) {
+  switch (level) {
+    case LogLevel::ARROW_TRACE:
+      return opentelemetry::logs::Severity::kTrace;
+    case LogLevel::ARROW_DEBUG:
+      return opentelemetry::logs::Severity::kDebug;
+    case LogLevel::ARROW_INFO:
+      return opentelemetry::logs::Severity::kInfo;
+    case LogLevel::ARROW_WARNING:
+      return opentelemetry::logs::Severity::kWarn;
+    case LogLevel::ARROW_ERROR:
+      return opentelemetry::logs::Severity::kError;
+    case LogLevel::ARROW_FATAL:
+      return opentelemetry::logs::Severity::kFatal;
+  }
+  return otel::logs::Severity::kInvalid;
+}
+
+enum class ExporterKind {
+  OSTREAM,
+  OTLP_HTTP,
+  OTLP_OSTREAM,
+};
+
+std::unique_ptr<otel::sdk::logs::LogRecordExporter> MakeExporter(
+    ExporterKind exporter_kind, std::ostream* ostream = nullptr) {
+  switch (exporter_kind) {
+    case ExporterKind::OSTREAM: {
+      return 
std::make_unique<otel::exporter::logs::OStreamLogRecordExporter>(*ostream);
+    } break;
+    case ExporterKind::OTLP_HTTP: {
+      namespace otlp = otel::exporter::otlp;
+      // TODO: Allow user configuration here?
+      otlp::OtlpHttpLogRecordExporterOptions options{};
+      return std::make_unique<otlp::OtlpHttpLogRecordExporter>(options);
+    } break;
+    case ExporterKind::OTLP_OSTREAM: {
+      return std::make_unique<OtlpOStreamLogRecordExporter>(ostream);
+    } break;
+    default:
+      break;
+  }
+  return nullptr;
+}
+
+std::unique_ptr<otel::sdk::logs::LogRecordExporter> MakeExporterFromEnv(
+    const LoggerProviderOptions& options) {
+  auto maybe_env_var = arrow::internal::GetEnvVar(kLoggingBackendEnvVar);
+  if (maybe_env_var.ok()) {
+    auto env_var = maybe_env_var.ValueOrDie();
+    auto* default_ostream =
+        options.default_export_stream ? options.default_export_stream : 
&std::cerr;
+    if (env_var == "ostream") {
+      // TODO: Currently disabled as the log records returned by otel's 
ostream exporter
+      // don't maintain copies of their attributes, leading to lifetime 
issues. If/when
+      // this is addressed, we can enable it. See:
+      // https://github.com/open-telemetry/opentelemetry-cpp/issues/2402
+#if 0
+      return MakeExporter(ExporterKind::OSTREAM, default_ostream);
+#else
+      ARROW_LOG(WARNING) << "Requested unimplemented backend " << 
kLoggingBackendEnvVar
+                         << "=" << env_var << ". Falling back to 
arrow_otlp_ostream";
+      return MakeExporter(ExporterKind::OTLP_OSTREAM, default_ostream);
+#endif
+    } else if (env_var == "otlp_http") {
+      return MakeExporter(ExporterKind::OTLP_HTTP);
+    } else if (env_var == "arrow_otlp_stdout") {
+      return MakeExporter(ExporterKind::OTLP_OSTREAM, &std::cout);
+    } else if (env_var == "arrow_otlp_stderr") {
+      return MakeExporter(ExporterKind::OTLP_OSTREAM, &std::cerr);
+    } else if (env_var == "arrow_otlp_ostream") {
+      return MakeExporter(ExporterKind::OTLP_OSTREAM, default_ostream);
+    } else if (!env_var.empty()) {
+      ARROW_LOG(WARNING) << "Requested unknown backend " << 
kLoggingBackendEnvVar << "="
+                         << env_var;
+    }
+  }
+  return nullptr;
+}
+
+std::unique_ptr<otel::sdk::logs::LogRecordProcessor> MakeLogRecordProcessor(
+    std::unique_ptr<otel::sdk::logs::LogRecordExporter> exporter) {
+  otel::sdk::logs::BatchLogRecordProcessorOptions options{};
+  return 
std::make_unique<otel::sdk::logs::BatchLogRecordProcessor>(std::move(exporter),
+                                                                    options);
+}
+
+otel::sdk::resource::Resource MakeResource(const ServiceAttributes& 
service_attributes) {
+  // TODO: We could also include process info...

Review Comment:
   How could we get to a decision on whether to include these attributes? It 
seems like it could be useful information but, since users would typically be 
expected to correlate logs with traces, could this also be superfluous?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to