1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/debug/trace.h"
22 
23 #include <string>
24 #include <type_traits>
25 #include <utility>
26 
27 #include "absl/strings/ascii.h"
28 #include "absl/strings/match.h"
29 #include "absl/strings/str_split.h"
30 #include "absl/strings/string_view.h"
31 
32 #include <grpc/grpc.h>
33 #include <grpc/support/log.h>
34 
35 #include "src/core/lib/config/config_vars.h"
36 
37 int grpc_tracer_set_enabled(const char* name, int enabled);
38 
39 namespace grpc_core {
40 
41 TraceFlag* TraceFlagList::root_tracer_ = nullptr;
42 
Set(absl::string_view name,bool enabled)43 bool TraceFlagList::Set(absl::string_view name, bool enabled) {
44   TraceFlag* t;
45   if (name == "all") {
46     for (t = root_tracer_; t; t = t->next_tracer_) {
47       t->set_enabled(enabled);
48     }
49   } else if (name == "list_tracers") {
50     LogAllTracers();
51   } else if (name == "refcount") {
52     for (t = root_tracer_; t; t = t->next_tracer_) {
53       if (absl::StrContains(t->name_, "refcount")) {
54         t->set_enabled(enabled);
55       }
56     }
57   } else {
58     bool found = false;
59     for (t = root_tracer_; t; t = t->next_tracer_) {
60       if (name == t->name_) {
61         t->set_enabled(enabled);
62         found = true;
63       }
64     }
65     // check for unknowns, but ignore "", to allow to GRPC_TRACE=
66     if (!found && !name.empty()) {
67       gpr_log(GPR_ERROR, "Unknown trace var: '%s'", std::string(name).c_str());
68       return false;  // early return
69     }
70   }
71   return true;
72 }
73 
Add(TraceFlag * flag)74 void TraceFlagList::Add(TraceFlag* flag) {
75   flag->next_tracer_ = root_tracer_;
76   root_tracer_ = flag;
77 }
78 
LogAllTracers()79 void TraceFlagList::LogAllTracers() {
80   gpr_log(GPR_DEBUG, "available tracers:");
81   for (TraceFlag* t = root_tracer_; t != nullptr; t = t->next_tracer_) {
82     gpr_log(GPR_DEBUG, "\t%s", t->name_);
83   }
84 }
85 
SaveTo(std::map<std::string,bool> & values)86 void TraceFlagList::SaveTo(std::map<std::string, bool>& values) {
87   for (TraceFlag* t = root_tracer_; t != nullptr; t = t->next_tracer_) {
88     values[t->name_] = t->enabled();
89   }
90 }
91 
92 // Flags register themselves on the list during construction
TraceFlag(bool default_enabled,const char * name)93 TraceFlag::TraceFlag(bool default_enabled, const char* name) : name_(name) {
94   static_assert(std::is_trivially_destructible<TraceFlag>::value,
95                 "TraceFlag needs to be trivially destructible.");
96   set_enabled(default_enabled);
97   TraceFlagList::Add(this);
98 }
99 
SavedTraceFlags()100 SavedTraceFlags::SavedTraceFlags() { TraceFlagList::SaveTo(values_); }
101 
Restore()102 void SavedTraceFlags::Restore() {
103   for (const auto& flag : values_) {
104     TraceFlagList::Set(flag.first, flag.second);
105   }
106 }
107 
108 namespace {
ParseTracers(absl::string_view tracers)109 void ParseTracers(absl::string_view tracers) {
110   for (auto s : absl::StrSplit(tracers, ',')) {
111     s = absl::StripAsciiWhitespace(s);
112     if (s.empty()) continue;
113     if (s[0] == '-') {
114       TraceFlagList::Set(s.substr(1), false);
115     } else {
116       TraceFlagList::Set(s, true);
117     }
118   }
119 }
120 }  // namespace
121 
122 }  // namespace grpc_core
123 
grpc_tracer_init()124 void grpc_tracer_init() {
125   grpc_core::ParseTracers(grpc_core::ConfigVars::Get().Trace());
126 }
127 
grpc_tracer_set_enabled(const char * name,int enabled)128 int grpc_tracer_set_enabled(const char* name, int enabled) {
129   return grpc_core::TraceFlagList::Set(name, enabled != 0);
130 }
131