pw_log_sink: Switch backing sink to multisink
Change-Id: I954a4c777d5c874a5174fca80e16093ce393d468
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/38401
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Commit-Queue: Prashanth Swaminathan <prashanthsw@google.com>
diff --git a/pw_log_sink/BUILD b/pw_log_sink/BUILD
index 22334a7..19306ab 100644
--- a/pw_log_sink/BUILD
+++ b/pw_log_sink/BUILD
@@ -29,14 +29,16 @@
deps = [
"//pw_bytes",
"//pw_log:facade",
- "//pw_log_multisink:log_queue",
+ "//pw_multisink",
"//pw_preprocessor",
"//pw_status",
"//pw_sync:interrupt_spin_lock",
],
hdrs = [
"public/pw_log_sink/log_sink.h",
- "public_overrides/pw_log_backend/log_backend.h"
+ "public/pw_log_sink/multisink_adapter.h",
+ "public/pw_log_sink/sink.h",
+ "public_overrides/pw_log_backend/log_backend.h",
]
)
diff --git a/pw_log_sink/BUILD.gn b/pw_log_sink/BUILD.gn
index cb2c330..d7c6485 100644
--- a/pw_log_sink/BUILD.gn
+++ b/pw_log_sink/BUILD.gn
@@ -34,13 +34,15 @@
]
public = [
"public/pw_log_sink/log_sink.h",
+ "public/pw_log_sink/multisink_adapter.h",
+ "public/pw_log_sink/sink.h",
"public_overrides/pw_log_backend/log_backend.h",
]
sources = [ "log_sink.cc" ]
public_deps = [
"$dir_pw_bytes",
"$dir_pw_log:facade",
- "$dir_pw_log_multisink:log_queue",
+ "$dir_pw_multisink",
"$dir_pw_preprocessor",
"$dir_pw_status",
]
diff --git a/pw_log_sink/log_sink_test.cc b/pw_log_sink/log_sink_test.cc
index 3c58303..52f8bbe 100644
--- a/pw_log_sink/log_sink_test.cc
+++ b/pw_log_sink/log_sink_test.cc
@@ -19,6 +19,9 @@
#include "gtest/gtest.h"
#include "pw_log/levels.h"
#include "pw_log_proto/log.pwpb.h"
+#include "pw_log_sink/multisink_adapter.h"
+#include "pw_multisink/drain.h"
+#include "pw_multisink/multisink.h"
#include "pw_protobuf/decoder.h"
namespace pw::log_sink {
@@ -26,37 +29,19 @@
constexpr size_t kMaxTokenizedMessageSize = 512;
constexpr char kTokenizedMessage[] = "Test Message";
-class TestSink : public Sink {
- public:
- void HandleEntry(ConstByteSpan message) {
- pw::protobuf::Decoder log_decoder(message);
- std::string_view log_entry_message;
+std::string LogMessageToString(ConstByteSpan message) {
+ pw::protobuf::Decoder log_decoder(message);
+ std::string_view log_entry_message;
- EXPECT_TRUE(log_decoder.Next().ok()); // line_level - 2
- EXPECT_TRUE(log_decoder.Next().ok()); // flags - 3
- EXPECT_TRUE(log_decoder.Next().ok()); // timestamp - 5
- EXPECT_TRUE(log_decoder.Next().ok()); // message_string - 16
- EXPECT_EQ(16U, log_decoder.FieldNumber());
- EXPECT_TRUE(log_decoder.ReadString(&log_entry_message).ok());
+ EXPECT_TRUE(log_decoder.Next().ok()); // line_level - 2
+ EXPECT_TRUE(log_decoder.Next().ok()); // flags - 3
+ EXPECT_TRUE(log_decoder.Next().ok()); // timestamp - 5
+ EXPECT_TRUE(log_decoder.Next().ok()); // message_string - 16
+ EXPECT_EQ(16U, log_decoder.FieldNumber());
+ EXPECT_TRUE(log_decoder.ReadString(&log_entry_message).ok());
- last_message_string_ = log_entry_message;
- message_count_++;
- }
-
- void HandleDropped(size_t count) { drop_count_ += count; }
-
- void VerifyMessage(std::string tokenized_message) {
- EXPECT_EQ(tokenized_message, last_message_string_);
- }
-
- size_t GetMessageCount() { return message_count_; }
- size_t GetDropCount() { return drop_count_; }
-
- private:
- std::string last_message_string_;
- size_t message_count_ = 0;
- size_t drop_count_ = 0;
-};
+ return std::string(log_entry_message);
+}
void LogMessageForTest(const char* message) {
pw_LogSink_Log(0, 0, nullptr, nullptr, 0, nullptr, "%s", message);
@@ -70,6 +55,28 @@
pw_LogSink_Log(0, 0, nullptr, nullptr, 0, nullptr, "%s", long_message);
}
+class TestSink final : public Sink {
+ public:
+ void HandleEntry(ConstByteSpan message) final {
+ last_message_string_ = LogMessageToString(message);
+ message_count_++;
+ }
+
+ void HandleDropped(uint32_t count) final { drop_count_ += count; }
+
+ void VerifyMessage(std::string tokenized_message) {
+ EXPECT_EQ(tokenized_message, last_message_string_);
+ }
+
+ uint32_t GetMessageCount() { return message_count_; }
+ uint32_t GetDropCount() { return drop_count_; }
+
+ private:
+ std::string last_message_string_;
+ uint32_t message_count_ = 0;
+ uint32_t drop_count_ = 0;
+};
+
} // namespace
TEST(LogSink, NoSink) {
@@ -126,4 +133,25 @@
RemoveSink(test_sink);
}
+TEST(LogSink, MultiSinkAdapter) {
+ constexpr size_t kMultiSinkBufferSize = 1024;
+ std::byte buffer[kMultiSinkBufferSize];
+ std::byte entry_buffer[kMultiSinkBufferSize];
+ pw::multisink::MultiSink multisink(buffer);
+ pw::multisink::Drain drain;
+ MultiSinkAdapter multisink_adapter(multisink);
+
+ multisink.AttachDrain(drain);
+ LogMessageForTest(kTokenizedMessage);
+
+ AddSink(multisink_adapter);
+ LogMessageForTest(kTokenizedMessage);
+
+ uint32_t drop_count = 0;
+ Result<ConstByteSpan> entry = drain.GetEntry(entry_buffer, drop_count);
+ ASSERT_TRUE(entry.ok());
+ EXPECT_EQ(LogMessageToString(entry.value()), kTokenizedMessage);
+ EXPECT_EQ(drop_count, 1U);
+}
+
} // namespace pw::log_sink
diff --git a/pw_log_sink/public/pw_log_sink/log_sink.h b/pw_log_sink/public/pw_log_sink/log_sink.h
index fbed200..648f5c2 100644
--- a/pw_log_sink/public/pw_log_sink/log_sink.h
+++ b/pw_log_sink/public/pw_log_sink/log_sink.h
@@ -55,7 +55,7 @@
#include <string_view>
#include "pw_bytes/span.h"
-#include "pw_log_multisink/sink.h"
+#include "pw_log_sink/sink.h"
namespace pw::log_sink {
diff --git a/pw_log_sink/public/pw_log_sink/multisink_adapter.h b/pw_log_sink/public/pw_log_sink/multisink_adapter.h
new file mode 100644
index 0000000..af45cb2
--- /dev/null
+++ b/pw_log_sink/public/pw_log_sink/multisink_adapter.h
@@ -0,0 +1,45 @@
+// Copyright 2021 The Pigweed Authors
+//
+// 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
+//
+// https://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 "pw_log_sink/sink.h"
+#include "pw_multisink/multisink.h"
+
+namespace pw {
+namespace log_sink {
+
+class MultiSinkAdapter final : public Sink {
+ public:
+ MultiSinkAdapter(multisink::MultiSink& multisink) : multisink_(multisink) {}
+
+ // Write an entry to the sink.
+ void HandleEntry(ConstByteSpan entry) final {
+ // Best-effort attempt to send data to the sink, so status is ignored. The
+ // multisink handles failures internally and propagates them to its drains.
+ multisink_.HandleEntry(entry);
+ }
+
+ // Notifies the sink of messages dropped before ingress. The writer may use
+ // this to signal to sinks that an entry (or entries) was lost before sending
+ // to the sink (e.g. the log sink failed to encode the message).
+ void HandleDropped(uint32_t drop_count) final {
+ multisink_.HandleDropped(drop_count);
+ }
+
+ private:
+ multisink::MultiSink& multisink_;
+};
+
+} // namespace log_sink
+} // namespace pw
diff --git a/pw_log_sink/public/pw_log_sink/sink.h b/pw_log_sink/public/pw_log_sink/sink.h
new file mode 100644
index 0000000..a85b5b5
--- /dev/null
+++ b/pw_log_sink/public/pw_log_sink/sink.h
@@ -0,0 +1,40 @@
+// Copyright 2021 The Pigweed Authors
+//
+// 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
+//
+// https://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
+
+// TODO(pwbug.dev/351): This file is very similar to pw_log_multisink/sink.h,
+// which will be deprecated in a later change.
+
+#include "pw_bytes/span.h"
+#include "pw_containers/intrusive_list.h"
+
+namespace pw {
+namespace log_sink {
+
+class Sink : public IntrusiveList<Sink>::Item {
+ public:
+ virtual ~Sink() = default;
+
+ // Write an entry to the sink. This is a best-effort attempt to send data to
+ // the sink, so failures are ignored.
+ virtual void HandleEntry(ConstByteSpan entry) = 0;
+
+ // Notifies the sink of messages dropped before ingress. The writer may use
+ // this to signal to sinks that an entry (or entries) was lost before sending
+ // to the sink (e.g. the log sink failed to encode the message).
+ virtual void HandleDropped(uint32_t drop_count) = 0;
+};
+
+} // namespace log_sink
+} // namespace pw