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/match.h"
28 #include "absl/strings/str_split.h"
29 #include "absl/strings/string_view.h"
30
31 #include <grpc/grpc.h>
32 #include <grpc/support/log.h>
33
34 #include "src/core/lib/config/config_vars.h"
35
36 int grpc_tracer_set_enabled(const char* name, int enabled);
37
38 namespace grpc_core {
39
40 TraceFlag* TraceFlagList::root_tracer_ = nullptr;
41
Set(absl::string_view name,bool enabled)42 bool TraceFlagList::Set(absl::string_view name, bool enabled) {
43 TraceFlag* t;
44 if (name == "all") {
45 for (t = root_tracer_; t; t = t->next_tracer_) {
46 t->set_enabled(enabled);
47 }
48 } else if (name == "list_tracers") {
49 LogAllTracers();
50 } else if (name == "refcount") {
51 for (t = root_tracer_; t; t = t->next_tracer_) {
52 if (absl::StrContains(t->name_, "refcount")) {
53 t->set_enabled(enabled);
54 }
55 }
56 } else {
57 bool found = false;
58 for (t = root_tracer_; t; t = t->next_tracer_) {
59 if (name == t->name_) {
60 t->set_enabled(enabled);
61 found = true;
62 }
63 }
64 // check for unknowns, but ignore "", to allow to GRPC_TRACE=
65 if (!found && !name.empty()) {
66 gpr_log(GPR_ERROR, "Unknown trace var: '%s'", std::string(name).c_str());
67 return false; // early return
68 }
69 }
70 return true;
71 }
72
Add(TraceFlag * flag)73 void TraceFlagList::Add(TraceFlag* flag) {
74 flag->next_tracer_ = root_tracer_;
75 root_tracer_ = flag;
76 }
77
LogAllTracers()78 void TraceFlagList::LogAllTracers() {
79 gpr_log(GPR_DEBUG, "available tracers:");
80 for (TraceFlag* t = root_tracer_; t != nullptr; t = t->next_tracer_) {
81 gpr_log(GPR_DEBUG, "\t%s", t->name_);
82 }
83 }
84
SaveTo(std::map<std::string,bool> & values)85 void TraceFlagList::SaveTo(std::map<std::string, bool>& values) {
86 for (TraceFlag* t = root_tracer_; t != nullptr; t = t->next_tracer_) {
87 values[t->name_] = t->enabled();
88 }
89 }
90
91 // Flags register themselves on the list during construction
TraceFlag(bool default_enabled,const char * name)92 TraceFlag::TraceFlag(bool default_enabled, const char* name) : name_(name) {
93 static_assert(std::is_trivially_destructible<TraceFlag>::value,
94 "TraceFlag needs to be trivially destructible.");
95 set_enabled(default_enabled);
96 TraceFlagList::Add(this);
97 }
98
SavedTraceFlags()99 SavedTraceFlags::SavedTraceFlags() { TraceFlagList::SaveTo(values_); }
100
Restore()101 void SavedTraceFlags::Restore() {
102 for (const auto& flag : values_) {
103 TraceFlagList::Set(flag.first, flag.second);
104 }
105 }
106
107 namespace {
ParseTracers(absl::string_view tracers)108 void ParseTracers(absl::string_view tracers) {
109 for (auto s : absl::StrSplit(tracers, ',', absl::SkipWhitespace())) {
110 if (s[0] == '-') {
111 TraceFlagList::Set(s.substr(1), false);
112 } else {
113 TraceFlagList::Set(s, true);
114 }
115 }
116 }
117 } // namespace
118
119 } // namespace grpc_core
120
grpc_tracer_init()121 void grpc_tracer_init() {
122 grpc_core::ParseTracers(grpc_core::ConfigVars::Get().Trace());
123 }
124
grpc_tracer_set_enabled(const char * name,int enabled)125 int grpc_tracer_set_enabled(const char* name, int enabled) {
126 return grpc_core::TraceFlagList::Set(name, enabled != 0);
127 }
128