• 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_log_rpc/log_filter.h"
16 
17 #include "pw_log/levels.h"
18 #include "pw_protobuf/decoder.h"
19 #include "pw_status/try.h"
20 
21 namespace pw::log_rpc {
22 namespace {
23 
24 // Returns true if the provided log parameters match the given filter rule.
IsRuleMet(const Filter::Rule & rule,uint32_t level,ConstByteSpan module,uint32_t flags)25 bool IsRuleMet(const Filter::Rule& rule,
26                uint32_t level,
27                ConstByteSpan module,
28                uint32_t flags) {
29   if (level < static_cast<uint32_t>(rule.level_greater_than_or_equal)) {
30     return false;
31   }
32   if ((rule.any_flags_set != 0) && ((flags & rule.any_flags_set) == 0)) {
33     return false;
34   }
35   if (!rule.module_equals.empty() && !std::equal(module.begin(),
36                                                  module.end(),
37                                                  rule.module_equals.begin(),
38                                                  rule.module_equals.end())) {
39     return false;
40   }
41   return true;
42 }
43 
44 }  // namespace
45 
UpdateRulesFromProto(ConstByteSpan buffer)46 Status Filter::UpdateRulesFromProto(ConstByteSpan buffer) {
47   if (rules_.empty()) {
48     return Status::FailedPrecondition();
49   }
50 
51   // Reset rules.
52   for (auto& rule : rules_) {
53     rule = {};
54   }
55 
56   protobuf::Decoder decoder(buffer);
57   Status status;
58   for (size_t i = 0; (i < rules_.size()) && (status = decoder.Next()).ok();
59        ++i) {
60     ConstByteSpan rule_buffer;
61     PW_TRY(decoder.ReadBytes(&rule_buffer));
62     protobuf::Decoder rule_decoder(rule_buffer);
63     while ((status = rule_decoder.Next()).ok()) {
64       switch (
65           static_cast<log::FilterRule::Fields>(rule_decoder.FieldNumber())) {
66         case log::FilterRule::Fields::LEVEL_GREATER_THAN_OR_EQUAL:
67           PW_TRY(rule_decoder.ReadUint32(reinterpret_cast<uint32_t*>(
68               &rules_[i].level_greater_than_or_equal)));
69           break;
70         case log::FilterRule::Fields::MODULE_EQUALS: {
71           ConstByteSpan module;
72           PW_TRY(rule_decoder.ReadBytes(&module));
73           if (module.size() > rules_[i].module_equals.max_size()) {
74             return Status::InvalidArgument();
75           }
76           rules_[i].module_equals.assign(module.begin(), module.end());
77         } break;
78         case log::FilterRule::Fields::ANY_FLAGS_SET:
79           PW_TRY(rule_decoder.ReadUint32(&rules_[i].any_flags_set));
80           break;
81         case log::FilterRule::Fields::ACTION:
82           PW_TRY(rule_decoder.ReadUint32(
83               reinterpret_cast<uint32_t*>(&rules_[i].action)));
84           break;
85       }
86     }
87   }
88   return status.IsOutOfRange() ? OkStatus() : status;
89 }
90 
ShouldDropLog(ConstByteSpan entry) const91 bool Filter::ShouldDropLog(ConstByteSpan entry) const {
92   if (rules_.empty()) {
93     return false;
94   }
95 
96   uint32_t log_level = 0;
97   ConstByteSpan log_module;
98   uint32_t log_flags = 0;
99   protobuf::Decoder decoder(entry);
100   while (decoder.Next().ok()) {
101     switch (static_cast<log::LogEntry::Fields>(decoder.FieldNumber())) {
102       case log::LogEntry::Fields::LINE_LEVEL:
103         if (decoder.ReadUint32(&log_level).ok()) {
104           log_level &= PW_LOG_LEVEL_BITMASK;
105         }
106         break;
107       case log::LogEntry::Fields::MODULE:
108         decoder.ReadBytes(&log_module).IgnoreError();
109         break;
110       case log::LogEntry::Fields::FLAGS:
111         decoder.ReadUint32(&log_flags).IgnoreError();
112         break;
113       default:
114         break;
115     }
116   }
117 
118   // Follow the action of the first rule whose condition is met.
119   for (const auto& rule : rules_) {
120     if (rule.action == Filter::Rule::Action::kInactive) {
121       continue;
122     }
123     if (IsRuleMet(rule, log_level, log_module, log_flags)) {
124       return rule.action == Filter::Rule::Action::kDrop;
125     }
126   }
127 
128   return false;
129 }
130 
131 }  // namespace pw::log_rpc
132