Keir Mierle | 45fa785 | 2020-08-10 21:09:54 -0700 | [diff] [blame] | 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 | |
Wyatt Hepler | f298de4 | 2021-03-19 15:06:36 -0700 | [diff] [blame] | 20 | #include "pw_assert/check.h" |
Keir Mierle | 45fa785 | 2020-08-10 21:09:54 -0700 | [diff] [blame] | 21 | #include "pw_log/log.h" |
| 22 | #include "pw_tokenizer/base64.h" |
| 23 | |
| 24 | namespace pw::metric { |
| 25 | namespace { |
| 26 | |
| 27 | template <typename T> |
| 28 | std::span<const std::byte> AsSpan(const T& t) { |
| 29 | return std::span<const std::byte>(reinterpret_cast<const std::byte*>(&t), |
| 30 | sizeof(t)); |
| 31 | } |
| 32 | |
| 33 | // A convenience class to encode a token as base64 while managing the storage. |
| 34 | // TODO(keir): Consider putting this into upstream pw_tokenizer. |
| 35 | struct Base64EncodedToken { |
| 36 | Base64EncodedToken(Token token) { |
| 37 | int encoded_size = tokenizer::PrefixedBase64Encode(AsSpan(token), data); |
| 38 | data[encoded_size] = 0; |
| 39 | } |
| 40 | |
| 41 | const char* value() { return data.data(); } |
| 42 | std::array<char, 16> data; |
| 43 | }; |
| 44 | |
| 45 | const char* Indent(int level) { |
| 46 | static const char* kWhitespace8 = " "; |
| 47 | level = std::min(level, 4); |
| 48 | return kWhitespace8 + 8 - 2 * level; |
| 49 | } |
| 50 | |
| 51 | } // namespace |
| 52 | |
| 53 | // Enable easier registration when used as a member. |
| 54 | Metric::Metric(Token name, float value, IntrusiveList<Metric>& metrics) |
| 55 | : Metric(name, value) { |
| 56 | metrics.push_front(*this); |
| 57 | } |
| 58 | Metric::Metric(Token name, uint32_t value, IntrusiveList<Metric>& metrics) |
| 59 | : Metric(name, value) { |
| 60 | metrics.push_front(*this); |
| 61 | } |
| 62 | |
Keir Mierle | 9b51cdf | 2020-08-19 09:46:19 -0700 | [diff] [blame] | 63 | float Metric::as_float() const { |
| 64 | PW_DCHECK(is_float()); |
| 65 | return float_; |
| 66 | } |
| 67 | |
| 68 | uint32_t Metric::as_int() const { |
| 69 | PW_DCHECK(is_int()); |
| 70 | return uint_; |
| 71 | } |
| 72 | |
| 73 | void Metric::Increment(uint32_t amount) { |
| 74 | PW_DCHECK(is_int()); |
| 75 | uint_ += amount; |
| 76 | } |
| 77 | |
| 78 | void Metric::SetInt(uint32_t value) { |
| 79 | PW_DCHECK(is_int()); |
| 80 | uint_ = value; |
| 81 | } |
| 82 | |
| 83 | void Metric::SetFloat(float value) { |
| 84 | PW_DCHECK(is_float()); |
| 85 | float_ = value; |
| 86 | } |
| 87 | |
Keir Mierle | 45fa785 | 2020-08-10 21:09:54 -0700 | [diff] [blame] | 88 | void Metric::Dump(int level) { |
| 89 | Base64EncodedToken encoded_name(name()); |
| 90 | const char* indent = Indent(level); |
| 91 | if (is_float()) { |
| 92 | PW_LOG_INFO("%s \"%s\": %f,", indent, encoded_name.value(), as_float()); |
| 93 | } else { |
| 94 | PW_LOG_INFO("%s \"%s\": %u,", |
| 95 | indent, |
| 96 | encoded_name.value(), |
| 97 | static_cast<unsigned int>(as_int())); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | void Metric::Dump(IntrusiveList<Metric>& metrics, int level) { |
| 102 | for (auto& m : metrics) { |
| 103 | m.Dump(level); |
| 104 | } |
| 105 | } |
| 106 | |
Keir Mierle | 9b51cdf | 2020-08-19 09:46:19 -0700 | [diff] [blame] | 107 | Group::Group(Token name) : name_(name) {} |
| 108 | |
| 109 | Group::Group(Token name, IntrusiveList<Group>& groups) : name_(name) { |
| 110 | groups.push_front(*this); |
| 111 | } |
| 112 | |
Keir Mierle | 45fa785 | 2020-08-10 21:09:54 -0700 | [diff] [blame] | 113 | void Group::Dump(int level) { |
| 114 | Base64EncodedToken encoded_name(name()); |
| 115 | const char* indent = Indent(level); |
| 116 | PW_LOG_INFO("%s \"%s\": {", indent, encoded_name.value()); |
| 117 | Group::Dump(children(), level + 1); |
| 118 | Metric::Dump(metrics(), level + 1); |
| 119 | PW_LOG_INFO("%s }", indent); |
| 120 | } |
| 121 | |
| 122 | void Group::Dump(IntrusiveList<Group>& groups, int level) { |
| 123 | for (auto& group : groups) { |
| 124 | group.Dump(level); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | } // namespace pw::metric |