• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_metric/metric.h"
16 
17 #include <array>
18 #include <span>
19 
20 #include "pw_log/log.h"
21 #include "pw_tokenizer/base64.h"
22 
23 namespace pw::metric {
24 namespace {
25 
26 template <typename T>
AsSpan(const T & t)27 std::span<const std::byte> AsSpan(const T& t) {
28   return std::span<const std::byte>(reinterpret_cast<const std::byte*>(&t),
29                                     sizeof(t));
30 }
31 
32 // A convenience class to encode a token as base64 while managing the storage.
33 // TODO(keir): Consider putting this into upstream pw_tokenizer.
34 struct Base64EncodedToken {
Base64EncodedTokenpw::metric::__anon9c2b5a7d0111::Base64EncodedToken35   Base64EncodedToken(Token token) {
36     int encoded_size = tokenizer::PrefixedBase64Encode(AsSpan(token), data);
37     data[encoded_size] = 0;
38   }
39 
valuepw::metric::__anon9c2b5a7d0111::Base64EncodedToken40   const char* value() { return data.data(); }
41   std::array<char, 16> data;
42 };
43 
Indent(int level)44 const char* Indent(int level) {
45   static const char* kWhitespace8 = "        ";
46   level = std::min(level, 4);
47   return kWhitespace8 + 8 - 2 * level;
48 }
49 
50 }  // namespace
51 
52 // Enable easier registration when used as a member.
Metric(Token name,float value,IntrusiveList<Metric> & metrics)53 Metric::Metric(Token name, float value, IntrusiveList<Metric>& metrics)
54     : Metric(name, value) {
55   metrics.push_front(*this);
56 }
Metric(Token name,uint32_t value,IntrusiveList<Metric> & metrics)57 Metric::Metric(Token name, uint32_t value, IntrusiveList<Metric>& metrics)
58     : Metric(name, value) {
59   metrics.push_front(*this);
60 }
61 
as_float() const62 float Metric::as_float() const {
63   PW_DCHECK(is_float());
64   return float_;
65 }
66 
as_int() const67 uint32_t Metric::as_int() const {
68   PW_DCHECK(is_int());
69   return uint_;
70 }
71 
Increment(uint32_t amount)72 void Metric::Increment(uint32_t amount) {
73   PW_DCHECK(is_int());
74   uint_ += amount;
75 }
76 
SetInt(uint32_t value)77 void Metric::SetInt(uint32_t value) {
78   PW_DCHECK(is_int());
79   uint_ = value;
80 }
81 
SetFloat(float value)82 void Metric::SetFloat(float value) {
83   PW_DCHECK(is_float());
84   float_ = value;
85 }
86 
Dump(int level)87 void Metric::Dump(int level) {
88   Base64EncodedToken encoded_name(name());
89   const char* indent = Indent(level);
90   if (is_float()) {
91     PW_LOG_INFO("%s \"%s\": %f,", indent, encoded_name.value(), as_float());
92   } else {
93     PW_LOG_INFO("%s \"%s\": %u,",
94                 indent,
95                 encoded_name.value(),
96                 static_cast<unsigned int>(as_int()));
97   }
98 }
99 
Dump(IntrusiveList<Metric> & metrics,int level)100 void Metric::Dump(IntrusiveList<Metric>& metrics, int level) {
101   for (auto& m : metrics) {
102     m.Dump(level);
103   }
104 }
105 
Group(Token name)106 Group::Group(Token name) : name_(name) {}
107 
Group(Token name,IntrusiveList<Group> & groups)108 Group::Group(Token name, IntrusiveList<Group>& groups) : name_(name) {
109   groups.push_front(*this);
110 }
111 
Dump(int level)112 void Group::Dump(int level) {
113   Base64EncodedToken encoded_name(name());
114   const char* indent = Indent(level);
115   PW_LOG_INFO("%s \"%s\": {", indent, encoded_name.value());
116   Group::Dump(children(), level + 1);
117   Metric::Dump(metrics(), level + 1);
118   PW_LOG_INFO("%s }", indent);
119 }
120 
Dump(IntrusiveList<Group> & groups,int level)121 void Group::Dump(IntrusiveList<Group>& groups, int level) {
122   for (auto& group : groups) {
123     group.Dump(level);
124   }
125 }
126 
127 }  // namespace pw::metric
128