proxygen
StandardLogHandlerFactory.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
17 
18 #include <folly/MapUtil.h>
19 #include <folly/String.h>
24 
25 using std::string;
26 
27 namespace folly {
28 namespace {
29 
30 class GlogFormatterFactory
31  : public StandardLogHandlerFactory::FormatterFactory {
32  public:
33  bool processOption(StringPiece /* name */, StringPiece /* value */) override {
34  return false;
35  }
36  std::shared_ptr<LogFormatter> createFormatter(
37  const std::shared_ptr<LogWriter>& /* logWriter */) override {
38  return std::make_shared<GlogStyleFormatter>();
39  }
40 };
41 
42 class CustomLogFormatterFactory
43  : public StandardLogHandlerFactory::FormatterFactory {
44  public:
45  enum Colored { ALWAYS, AUTO, NEVER };
46 
47  bool processOption(StringPiece name, StringPiece value) override {
48  if (name == "log_format") {
49  format_ = value.str();
50  return true;
51  } else if (name == "colored") {
52  if (value == "always") {
53  colored_ = ALWAYS;
54  } else if (value == "auto") {
55  colored_ = AUTO;
56  } else if (value == "never") {
57  colored_ = NEVER;
58  } else {
59  throw std::invalid_argument(to<string>(
60  "unknown colored type \"",
61  value,
62  "\". Needs to be always/never/auto"));
63  }
64  return true;
65  }
66  return false;
67  }
68 
69  std::shared_ptr<LogFormatter> createFormatter(
70  const std::shared_ptr<LogWriter>& logWriter) override {
71  bool colored;
72  switch (colored_) {
73  case ALWAYS:
74  colored = true;
75  break;
76  case AUTO:
77  colored = logWriter->ttyOutput();
78  break;
79  case NEVER:
80  colored = false;
81  break;
82  }
83  return std::make_shared<CustomLogFormatter>(format_, colored);
84  }
85 
86  private:
88  Colored colored_{NEVER}; // Turn off coloring by default.
89 };
90 } // namespace
91 
92 std::shared_ptr<StandardLogHandler> StandardLogHandlerFactory::createHandler(
94  WriterFactory* writerFactory,
95  const Options& options) {
96  std::unique_ptr<FormatterFactory> formatterFactory;
97 
98  // Get the log formatter type
99  auto* formatterType = get_ptr(options, "formatter");
100  if (!formatterType || *formatterType == "glog") {
101  formatterFactory = std::make_unique<GlogFormatterFactory>();
102  } else if (!formatterType || *formatterType == "custom") {
103  formatterFactory = std::make_unique<CustomLogFormatterFactory>();
104  } else {
105  throw std::invalid_argument(
106  to<string>("unknown log formatter type \"", *formatterType, "\""));
107  }
108 
109  Optional<LogLevel> syncLevel;
110 
111  // Process the log formatter and log handler options
112  std::vector<string> errors;
113  for (const auto& entry : options) {
114  bool handled = false;
115  try {
116  // Allow both the formatterFactory and writerFactory to consume an
117  // option. In general they probably should have mutually exclusive
118  // option names, but we don't give precedence to one over the other here.
119  handled |= formatterFactory->processOption(entry.first, entry.second);
120  handled |= writerFactory->processOption(entry.first, entry.second);
121  } catch (const std::exception& ex) {
122  errors.push_back(to<string>(
123  "error processing option \"", entry.first, "\": ", ex.what()));
124  continue;
125  }
126 
127  // We explicitly processed the "formatter" option above.
128  handled |= handled || (entry.first == "formatter");
129 
130  // Process the "sync_level" option.
131  if (entry.first == "sync_level") {
132  try {
133  syncLevel = stringToLogLevel(entry.second);
134  } catch (const std::exception& ex) {
135  errors.push_back(to<string>(
136  "unable to parse value for option \"",
137  entry.first,
138  "\": ",
139  ex.what()));
140  }
141  handled = true;
142  }
143 
144  // Complain about unknown options.
145  if (!handled) {
146  errors.push_back(to<string>("unknown option \"", entry.first, "\""));
147  }
148  }
149 
150  if (!errors.empty()) {
151  throw std::invalid_argument(join(", ", errors));
152  }
153 
154  // Construct the formatter and writer
155  auto writer = writerFactory->createWriter();
156  auto formatter = formatterFactory->createFormatter(writer);
157 
158  if (syncLevel) {
159  return std::make_shared<StandardLogHandler>(
160  LogHandlerConfig{type, options}, formatter, writer, *syncLevel);
161  } else {
162  return std::make_shared<StandardLogHandler>(
163  LogHandlerConfig{type, options}, formatter, writer);
164  }
165 }
166 
167 } // namespace folly
const Map::mapped_type * get_ptr(const Map &map, const Key &key)
Definition: MapUtil.h:169
static std::shared_ptr< StandardLogHandler > createHandler(StringPiece type, WriterFactory *writerFactory, const Options &options)
virtual std::shared_ptr< LogWriter > createWriter()=0
Colored colored_
volatile bool handled
PskType type
virtual bool processOption(StringPiece name, StringPiece value)=0
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
LogLevel stringToLogLevel(StringPiece name)
Definition: LogLevel.cpp:42
const char * name
Definition: http_parser.c:437
std::unordered_map< std::string, std::string > Options
std::string format_
const char * string
Definition: Conv.cpp:212
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
void join(const Delim &delimiter, Iterator begin, Iterator end, String &output)
Definition: String-inl.h:498
Range< const char * > StringPiece