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