aboutsummaryrefslogtreecommitdiff
path: root/pw_trace_tokenized/trace_buffer_log.cc
blob: 8a58cc0dca800caccfb4e378f9555247a4538bdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// 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 "pw_base64/base64.h"
#include "pw_log/log.h"
#include "pw_span/span.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(span(entry_buffer).subspan(1), &bytes_read) !=
         pw::Status::OutOfRange()) {
    trace_buffer->PopFront()
        .IgnoreError();  // TODO(b/242598609): Handle Status properly
    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(span(entry_buffer, bytes_read + 1),
                                         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.empty()) {
    PW_LOG_INFO("[TRACE] data: %s", line_builder.c_str());
  }
  PW_LOG_INFO("[TRACE] end");
  return pw::OkStatus();
}

}  // namespace trace
}  // namespace pw