From 2e79399724b360e79628607e238b5c1639df7fb1 Mon Sep 17 00:00:00 2001 From: Rei Shimizu Date: Mon, 14 Jun 2021 14:39:17 +0900 Subject: [PATCH] implement log and trace integration (#79) --- README.md | 25 ++++++++++++++++++++++ cpp2sky/BUILD | 3 +++ cpp2sky/assert.h | 24 +++++++++++++++++++++ cpp2sky/time.h | 7 +++---- cpp2sky/trace_log.h | 38 ++++++++++++++++++++++++++++++++++ cpp2sky/tracing_context.h | 7 +++++++ source/BUILD | 2 +- source/tracing_context_impl.cc | 17 +++++++++++++++ source/tracing_context_impl.h | 1 + test/tracing_context_test.cc | 8 +++++++ 10 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 cpp2sky/assert.h create mode 100644 cpp2sky/trace_log.h diff --git a/README.md b/README.md index d575a69..4d7c157 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,31 @@ After setup configurations, try to put values with curl --request PUT --data-binary "@./config.yaml" http://localhost:8500/v1/kv/configuration-discovery.default.agentConfigurations ``` +## Trace and Log integration + +cpp2sky implements to output logs which is the key to integrate with actual tracing context. + +#### Supported Logger + +- [spdlog](https://github.com/gabime/spdlog) + +```cpp +#include +#include + +int main() { + auto logger = spdlog::default_logger(); + // set_pattern must be called. + logger->set_pattern(logFormat()); + + // It will generate log message as follows. + // + // {"level": "warning", "msg": "sample", "SW_CTX": ["service","instance","trace_id","segment_id","span_id"]} + // + logger->warn(tracing_context->logMessage("sample")); +} +``` + ## Security If you've found any security issues, please read [Security Reporting Process](https://github.com/SkyAPM/cpp2sky/blob/main/SECURITY.md) and take described steps. diff --git a/cpp2sky/BUILD b/cpp2sky/BUILD index 420abbe..59555b9 100644 --- a/cpp2sky/BUILD +++ b/cpp2sky/BUILD @@ -23,6 +23,8 @@ cc_library( "well_known_names.h", "exception.h", "time.h", + "assert.h", + "trace_log.h", ], deps = [ ":config_cc_proto", @@ -38,6 +40,7 @@ cc_library( "well_known_names.h", "exception.h", "time.h", + "assert.h", ], deps = [ ":config_cc_proto", diff --git a/cpp2sky/assert.h b/cpp2sky/assert.h new file mode 100644 index 0000000..b083a65 --- /dev/null +++ b/cpp2sky/assert.h @@ -0,0 +1,24 @@ +// Copyright 2020 SkyAPM + +// Licensed 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. + +#pragma once + +namespace cpp2sky { + +template +static constexpr bool false_v = false; + +#define CPP2SKY_STATIC_ASSERT(T, m) static_assert(false_v, m) + +} // namespace cpp2sky diff --git a/cpp2sky/time.h b/cpp2sky/time.h index 6e4cad7..17bef91 100644 --- a/cpp2sky/time.h +++ b/cpp2sky/time.h @@ -16,17 +16,16 @@ #include +#include "cpp2sky/assert.h" + namespace cpp2sky { using SystemTime = std::chrono::system_clock::time_point; using SteadyTime = std::chrono::steady_clock::time_point; -template -static constexpr bool false_v = false; - template class TimePoint { - static_assert(false_v, "Invalid time type"); + CPP2SKY_STATIC_ASSERT(T, "Invalid time type"); }; template <> diff --git a/cpp2sky/trace_log.h b/cpp2sky/trace_log.h new file mode 100644 index 0000000..323f6e6 --- /dev/null +++ b/cpp2sky/trace_log.h @@ -0,0 +1,38 @@ +// Copyright 2021 SkyAPM + +// Licensed 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. + +#pragma once + +#include + +#include +#include + +#include "cpp2sky/assert.h" + +namespace cpp2sky { + +static constexpr std::string_view SPDLOG_LOG_FORMAT = + "{\"level\": \"%^%l%$\", \"msg\": \"%v"; + +template +std::string logFormat() { + if constexpr (std::is_same_v) { + return SPDLOG_LOG_FORMAT.data(); + } else { + CPP2SKY_STATIC_ASSERT(T, "non-supported logger type"); + } +} + +} // namespace cpp2sky diff --git a/cpp2sky/tracing_context.h b/cpp2sky/tracing_context.h index 7353b72..c21d58e 100644 --- a/cpp2sky/tracing_context.h +++ b/cpp2sky/tracing_context.h @@ -264,6 +264,13 @@ class TracingContext { * Determine whether to send this segment or not. */ virtual bool readyToSend() = 0; + + /** + * Get log message. Output value of this function is based on default cpp2sky + * logging format following with any format extracted with + * cpp2sky::logFormat(). + */ + virtual std::string logMessage(std::string_view message) const = 0; }; using TracingContextPtr = std::shared_ptr; diff --git a/source/BUILD b/source/BUILD index f3ae15b..f20125c 100644 --- a/source/BUILD +++ b/source/BUILD @@ -8,7 +8,7 @@ cc_library( "grpc_async_client_impl.h", "tracer_impl.h", "cds_impl.h", - "dynamic_config.h" + "dynamic_config.h", ], srcs = [ "propagation_impl.cc", diff --git a/source/tracing_context_impl.cc b/source/tracing_context_impl.cc index 0ddb303..1aa7f17 100644 --- a/source/tracing_context_impl.cc +++ b/source/tracing_context_impl.cc @@ -267,6 +267,23 @@ bool TracingContextImpl::readyToSend() { return true; } +std::string TracingContextImpl::logMessage(std::string_view message) const { + std::string output = message.data(); + output += "\", \"SW_CTX\": ["; + output += "\"" + service_ + "\","; + output += "\"" + service_instance_ + "\","; + output += "\"" + trace_id_ + "\","; + output += "\"" + trace_segment_id_ + "\","; + + if (!spans_.empty()) { + output += "\"" + std::to_string(spans_.back()->spanId()) + "\"]}"; + } else { + output += "\"-1\"]}"; + } + + return output; +} + TracingContextFactory::TracingContextFactory(const TracerConfig& config) : service_name_(config.service_name()), instance_name_(config.instance_name()) {} diff --git a/source/tracing_context_impl.h b/source/tracing_context_impl.h index 0db091e..5b36490 100644 --- a/source/tracing_context_impl.h +++ b/source/tracing_context_impl.h @@ -155,6 +155,7 @@ class TracingContextImpl : public TracingContext { void setSkipAnalysis() override { should_skip_analysis_ = true; } bool skipAnalysis() override { return should_skip_analysis_; } bool readyToSend() override; + std::string logMessage(std::string_view message) const override; private: std::string encodeSpan(TracingSpanPtr parent_span, diff --git a/test/tracing_context_test.cc b/test/tracing_context_test.cc index c72742d..8eab6b7 100644 --- a/test/tracing_context_test.cc +++ b/test/tracing_context_test.cc @@ -372,4 +372,12 @@ TEST_F(TracingContextTest, ReadyToSendTest) { EXPECT_FALSE(sc->readyToSend()); } +TEST_F(TracingContextTest, TraceLogTest) { + TracingContextImpl sc(config_.service_name(), config_.instance_name(), + span_ctx_, span_ext_ctx_, random_); + EXPECT_EQ( + "test\", \"SW_CTX\": [\"mesh\",\"service_0\",\"1\",\"uuid\",\"-1\"]}", + sc.logMessage("test")); +} + } // namespace cpp2sky