pw_trace_tokenized: Dump trace buffer to log
Adds a support function that dumps the current trace buffer using the
pw_log module.
Change-Id: Ie3b5bb666602ed0b0f294514e8c55646fba5c902
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/18160
Reviewed-by: Paul Mathieu <paulmathieu@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Prashanth Swaminathan <prashanthsw@google.com>
diff --git a/pw_trace_tokenized/BUILD b/pw_trace_tokenized/BUILD
index 6b853ea..00981e7 100644
--- a/pw_trace_tokenized/BUILD
+++ b/pw_trace_tokenized/BUILD
@@ -87,6 +87,22 @@
)
pw_cc_library(
+ name = "pw_trace_tokenized_buffer_log",
+ hdrs = [
+ "public/pw_trace_tokenized/trace_buffer_log.h",
+ ],
+ srcs = [
+ "trace_buffer_log.cc",
+ ],
+ deps = [
+ ":trace_buffer_headers",
+ "//pw_base64",
+ "//pw_log",
+ "//pw_string",
+ ],
+)
+
+pw_cc_library(
name = "pw_trace_tokenized_fake_time",
srcs = [
"fake_trace_time.cc",
@@ -128,6 +144,20 @@
],
)
+pw_cc_test(
+ name = "trace_tokenized_buffer_log_test",
+ srcs = [
+ "trace_buffer_log_test.cc",
+ ],
+ deps = [
+ ":backend",
+ ":facade",
+ ":pw_trace_log",
+ "//pw_preprocessor",
+ "//pw_unit_test",
+ ],
+)
+
pw_cc_library(
name = "pw_trace_host_trace_time",
includes = [ "example/public" ],
diff --git a/pw_trace_tokenized/BUILD.gn b/pw_trace_tokenized/BUILD.gn
index 3f0bed4..d0af5be 100644
--- a/pw_trace_tokenized/BUILD.gn
+++ b/pw_trace_tokenized/BUILD.gn
@@ -37,6 +37,7 @@
tests = [
":trace_tokenized_test",
":tokenized_trace_buffer_test",
+ ":tokenized_trace_buffer_log_test",
]
}
@@ -96,6 +97,26 @@
sources = [ "trace_buffer_test.cc" ]
}
+pw_source_set("tokenized_trace_buffer_log") {
+ deps = [
+ "$dir_pw_base64",
+ "$dir_pw_log",
+ "$dir_pw_string",
+ ]
+ public_deps = [ ":tokenized_trace_buffer" ]
+ sources = [ "trace_buffer_log.cc" ]
+ public = [ "public/pw_trace_tokenized/trace_buffer_log.h" ]
+}
+
+pw_test("tokenized_trace_buffer_log_test") {
+ enable_if = pw_trace_tokenizer_time != ""
+ deps = [
+ ":tokenized_trace_buffer_log",
+ "$dir_pw_trace",
+ ]
+ sources = [ "trace_buffer_log_test.cc" ]
+}
+
pw_source_set("fake_trace_time") {
deps = [ ":pw_trace_tokenized_core" ]
sources = [ "fake_trace_time.cc" ]
diff --git a/pw_trace_tokenized/docs.rst b/pw_trace_tokenized/docs.rst
index c588106..6548a03 100644
--- a/pw_trace_tokenized/docs.rst
+++ b/pw_trace_tokenized/docs.rst
@@ -182,6 +182,31 @@
``pw_varint``
+-------
+Logging
+-------
+The optional trace buffer logging adds support to dump trace buffers to the log.
+Buffers are converted to base64-encoding then split across log lines. Trace logs
+are surrounded by 'begin' and 'end' tags.
+
+Ex. Invoking PW_TRACE_INSTANT with 'test1' and 'test2', then calling this
+function would produce this in the output logs:
+
+.. code:: sh
+
+ [TRACE] begin
+ [TRACE] data: BWdDMRoABWj52YMB
+ [TRACE] end
+
+Added dependencies
+------------------
+``pw_base64``
+``pw_log``
+``pw_ring_buffer``
+``pw_string``
+``pw_tokenizer``
+``pw_varint``
+
--------
Examples
--------
diff --git a/pw_trace_tokenized/public/pw_trace_tokenized/trace_buffer_log.h b/pw_trace_tokenized/public/pw_trace_tokenized/trace_buffer_log.h
new file mode 100644
index 0000000..d6aa4f0
--- /dev/null
+++ b/pw_trace_tokenized/public/pw_trace_tokenized/trace_buffer_log.h
@@ -0,0 +1,37 @@
+// Copyright 2020 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.
+//==============================================================================
+//
+// This files provides support to dump the trace buffer to the logging module.
+#pragma once
+
+#include "pw_status/status.h"
+
+namespace pw {
+namespace trace {
+
+// Dumps the trace buffer to the log. The output format to the log is the
+// base64-encoded buffer, split into lines of an implementation-defined length.
+// The trace logs are surrounded by 'begin' and 'end' tags.
+//
+// Ex. Invoking PW_TRACE_INSTANT with 'test1' and 'test2', then calling this
+// function would produce this in the output logs:
+//
+// [TRACE] begin
+// [TRACE] data: BWdDMRoABWj52YMB
+// [TRACE] end
+pw::Status DumpTraceBufferToLog();
+
+} // namespace trace
+} // namespace pw
diff --git a/pw_trace_tokenized/trace_buffer_log.cc b/pw_trace_tokenized/trace_buffer_log.cc
new file mode 100644
index 0000000..3e41c3a
--- /dev/null
+++ b/pw_trace_tokenized/trace_buffer_log.cc
@@ -0,0 +1,85 @@
+// Copyright 2020 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.
+//==============================================================================
+//
+#include "pw_trace_tokenized/trace_buffer_log.h"
+
+#include <span>
+
+#include "pw_base64/base64.h"
+#include "pw_log/log.h"
+#include "pw_string/string_builder.h"
+#include "pw_trace_tokenized/trace_buffer.h"
+
+namespace pw {
+namespace trace {
+namespace {
+
+constexpr int kMaxEntrySize = PW_TRACE_BUFFER_MAX_BLOCK_SIZE_BYTES;
+constexpr int kMaxEntrySizeBase64 = pw::base64::EncodedSize(kMaxEntrySize);
+constexpr int kLineLength = 80;
+
+class ScopedTracePause {
+ public:
+ ScopedTracePause() : was_enabled_(pw_trace_IsEnabled()) {
+ PW_TRACE_SET_ENABLED(false);
+ }
+ ~ScopedTracePause() { PW_TRACE_SET_ENABLED(was_enabled_); }
+
+ private:
+ bool was_enabled_;
+};
+
+} // namespace
+
+pw::Status DumpTraceBufferToLog() {
+ std::byte line_buffer[kLineLength] = {};
+ std::byte entry_buffer[kMaxEntrySize + 1] = {};
+ char entry_base64_buffer[kMaxEntrySizeBase64] = {};
+ pw::StringBuilder line_builder(line_buffer);
+ ScopedTracePause pause_trace;
+ pw::ring_buffer::PrefixedEntryRingBuffer* trace_buffer =
+ pw::trace::GetBuffer();
+ size_t bytes_read = 0;
+ PW_LOG_INFO("[TRACE] begin");
+ while (trace_buffer->PeekFront(std::span(entry_buffer).subspan(1),
+ &bytes_read) != pw::Status::OUT_OF_RANGE) {
+ trace_buffer->PopFront();
+ entry_buffer[0] = static_cast<std::byte>(bytes_read);
+ // The entry buffer is formatted as (size, entry) with an extra byte as
+ // a header to the entry. The calcuation of bytes_read + 1 represents
+ // the extra size header.
+ size_t to_write =
+ pw::base64::Encode(std::span(entry_buffer, bytes_read + 1),
+ std::span(entry_base64_buffer));
+ size_t space_left = line_builder.max_size() - line_builder.size();
+ size_t written = 0;
+ while (to_write - written >= space_left) {
+ line_builder.append(entry_base64_buffer + written, space_left);
+ PW_LOG_INFO("[TRACE] data: %s", line_builder.c_str());
+ line_builder.clear();
+ written += space_left;
+ space_left = line_builder.max_size();
+ }
+ line_builder.append(entry_base64_buffer + written, to_write - written);
+ }
+ if (line_builder.size() > 0) {
+ PW_LOG_INFO("[TRACE] data: %s", line_builder.c_str());
+ }
+ PW_LOG_INFO("[TRACE] end");
+ return pw::Status::OK;
+}
+
+} // namespace trace
+} // namespace pw
diff --git a/pw_trace_tokenized/trace_buffer_log_test.cc b/pw_trace_tokenized/trace_buffer_log_test.cc
new file mode 100644
index 0000000..e2327e2
--- /dev/null
+++ b/pw_trace_tokenized/trace_buffer_log_test.cc
@@ -0,0 +1,43 @@
+// Copyright 2020 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.
+
+#define PW_TRACE_MODULE_NAME "TST"
+
+#include "pw_trace_tokenized/trace_buffer_log.h"
+
+#include "gtest/gtest.h"
+#include "pw_trace/trace.h"
+
+TEST(TokenizedTrace, DumpSmallBuffer) {
+ // TODO(pwbug/266): This test only verifies that the dump function does not
+ // crash, and requires manual inspection to confirm that the log output is
+ // correct. When there is support to mock and verify the calls to pw_log,
+ // these tests should be improved to validate the output.
+ PW_TRACE_SET_ENABLED(true);
+ PW_TRACE_INSTANT("test1");
+ PW_TRACE_INSTANT("test2");
+ pw::trace::DumpTraceBufferToLog();
+}
+
+TEST(TokenizedTrace, DumpLargeBuffer) {
+ // TODO(pwbug/266): This test only verifies that the dump function does not
+ // crash, and requires manual inspection to confirm that the log output is
+ // correct. When there is support to mock and verify the calls to pw_log,
+ // these tests should be improved to validate the output.
+ PW_TRACE_SET_ENABLED(true);
+ for (int i = 0; i < 100; i++) {
+ PW_TRACE_INSTANT("test");
+ }
+ pw::trace::DumpTraceBufferToLog();
+}