proxygen
LogCategory.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 <cstdio>
19 #include <cstdlib>
20 
21 #include <folly/ConstexprMath.h>
22 #include <folly/ExceptionString.h>
23 #include <folly/FileUtil.h>
24 #include <folly/MapUtil.h>
27 #include <folly/logging/LogName.h>
28 #include <folly/logging/LoggerDB.h>
29 
30 namespace folly {
31 
33  : effectiveLevel_{LogLevel::ERR},
34  level_{static_cast<uint32_t>(LogLevel::ERR)},
35  parent_{nullptr},
36  name_{},
37  db_{db} {}
38 
42  parent_{parent},
44  db_{parent->getDB()},
46  parent_->firstChild_ = this;
47 }
48 
50  processMessage(message);
51 
52  // If this is a fatal message, flush the handlers to make sure the log
53  // message was written out, then crash.
54  if (isLogLevelFatal(message.getLevel())) {
55  auto numHandlers = db_->flushAllHandlers();
56  if (numHandlers == 0) {
57  // No log handlers were configured.
58  // Print the message to stderr, to make sure we always print the reason
59  // we are crashing somewhere.
60  auto msg = folly::to<std::string>(
61  "FATAL:",
62  message.getFileName(),
63  ":",
64  message.getLineNumber(),
65  ": ",
66  message.getMessage(),
67  "\n");
68  folly::writeFull(STDERR_FILENO, msg.data(), msg.size());
69  }
70  std::abort();
71  }
72 }
73 
75  // Make a copy of any attached LogHandlers, so we can release the handlers_
76  // lock before holding them.
77  //
78  // In the common case there will only be a small number of handlers. Use a
79  // std::array in this case to avoid a heap allocation for the vector.
80  const std::shared_ptr<LogHandler>* handlers = nullptr;
81  size_t numHandlers = 0;
82  constexpr uint32_t kSmallOptimizationSize = 5;
83  std::array<std::shared_ptr<LogHandler>, kSmallOptimizationSize> handlersArray;
84  std::vector<std::shared_ptr<LogHandler>> handlersVector;
85  {
86  auto lockedHandlers = handlers_.rlock();
87  numHandlers = lockedHandlers->size();
88  if (numHandlers <= kSmallOptimizationSize) {
89  for (size_t n = 0; n < numHandlers; ++n) {
90  handlersArray[n] = (*lockedHandlers)[n];
91  }
92  handlers = handlersArray.data();
93  } else {
94  handlersVector = *lockedHandlers;
95  handlers = handlersVector.data();
96  }
97  }
98 
99  for (size_t n = 0; n < numHandlers; ++n) {
100  try {
101  handlers[n]->handleMessage(message, this);
102  } catch (const std::exception& ex) {
103  // Use LoggerDB::internalWarning() to report the error, but continue
104  // trying to log the message to any other handlers attached to ourself or
105  // one of our parent categories.
107  __FILE__,
108  __LINE__,
109  "log handler for category \"",
110  name_,
111  "\" threw an error: ",
112  folly::exceptionStr(ex));
113  }
114  }
115 
116  // Propagate the message up to our parent LogCategory.
117  //
118  // Maybe in the future it might be worth adding a flag to control if a
119  // LogCategory should propagate messages to its parent or not. (This would
120  // be similar to log4j's "additivity" flag.)
121  // For now I don't have a strong use case for this.
122  if (parent_) {
123  parent_->processMessage(message);
124  }
125 }
126 
127 void LogCategory::addHandler(std::shared_ptr<LogHandler> handler) {
128  auto handlers = handlers_.wlock();
129  handlers->emplace_back(std::move(handler));
130 }
131 
133  std::vector<std::shared_ptr<LogHandler>> emptyHandlersList;
134  // Swap out the handlers list with the handlers_ lock held.
135  {
136  auto handlers = handlers_.wlock();
137  handlers->swap(emptyHandlersList);
138  }
139  // Destroy emptyHandlersList now that the handlers_ lock is released.
140  // This way we don't hold the handlers_ lock while invoking any of the
141  // LogHandler destructors.
142 }
143 
144 std::vector<std::shared_ptr<LogHandler>> LogCategory::getHandlers() const {
145  return *(handlers_.rlock());
146 }
147 
149  std::vector<std::shared_ptr<LogHandler>> handlers) {
150  return handlers_.wlock()->swap(handlers);
151 }
152 
153 void LogCategory::updateHandlers(const std::unordered_map<
154  std::shared_ptr<LogHandler>,
155  std::shared_ptr<LogHandler>>& handlerMap) {
156  auto handlers = handlers_.wlock();
157  for (auto& entry : *handlers) {
158  auto* ptr = get_ptr(handlerMap, entry);
159  if (ptr) {
160  entry = *ptr;
161  }
162  }
163 }
164 
165 void LogCategory::setLevel(LogLevel level, bool inherit) {
166  // We have to set the level through LoggerDB, since we require holding
167  // the LoggerDB lock to iterate through our children in case our effective
168  // level changes.
169  db_->setLevel(this, level, inherit);
170 }
171 
172 void LogCategory::setLevelLocked(LogLevel level, bool inherit) {
173  // Clamp the value to MIN_LEVEL and MAX_LEVEL.
174  //
175  // This makes sure that UNINITIALIZED is always less than any valid level
176  // value, and that level values cannot conflict with our flag bits.
178 
179  // Make sure the inherit flag is always off for the root logger.
180  if (!parent_) {
181  inherit = false;
182  }
183  auto newValue = static_cast<uint32_t>(level);
184  if (inherit) {
185  newValue |= FLAG_INHERIT;
186  }
187 
188  // Update the stored value
189  uint32_t oldValue = level_.exchange(newValue, std::memory_order_acq_rel);
190 
191  // Break out early if the value has not changed.
192  if (oldValue == newValue) {
193  return;
194  }
195 
196  // Update the effective log level
197  LogLevel newEffectiveLevel;
198  if (inherit) {
199  newEffectiveLevel = std::min(level, parent_->getEffectiveLevel());
200  } else {
201  newEffectiveLevel = level;
202  }
203  updateEffectiveLevel(newEffectiveLevel);
204 }
205 
207  auto oldEffectiveLevel =
208  effectiveLevel_.exchange(newEffectiveLevel, std::memory_order_acq_rel);
209  // Break out early if the value did not change.
210  if (newEffectiveLevel == oldEffectiveLevel) {
211  return;
212  }
213 
214  // Update all of the values in xlogLevels_
215  for (auto* levelPtr : xlogLevels_) {
216  levelPtr->store(newEffectiveLevel, std::memory_order_release);
217  }
218 
219  // Update all children loggers
221  while (child != nullptr) {
222  child->parentLevelUpdated(newEffectiveLevel);
223  child = child->nextSibling_;
224  }
225 }
226 
227 void LogCategory::parentLevelUpdated(LogLevel parentEffectiveLevel) {
228  uint32_t levelValue = level_.load(std::memory_order_acquire);
229  auto inherit = (levelValue & FLAG_INHERIT);
230  if (!inherit) {
231  return;
232  }
233 
234  auto myLevel = static_cast<LogLevel>(levelValue & ~FLAG_INHERIT);
235  auto newEffectiveLevel = std::min(myLevel, parentEffectiveLevel);
236  updateEffectiveLevel(newEffectiveLevel);
237 }
238 
239 void LogCategory::registerXlogLevel(std::atomic<LogLevel>* levelPtr) {
240  xlogLevels_.push_back(levelPtr);
241 }
242 } // namespace folly
const Map::mapped_type * get_ptr(const Map &map, const Key &key)
Definition: MapUtil.h:169
folly::Synchronized< std::vector< std::shared_ptr< LogHandler > > > handlers_
Definition: LogCategory.h:272
void * ptr
Definition: test.c:42
LogCategory(LoggerDB *db)
Definition: LogCategory.cpp:32
std::atomic< uint32_t > level_
Definition: LogCategory.h:254
void processMessage(const LogMessage &message) const
Definition: LogCategory.cpp:74
std::vector< std::atomic< LogLevel > * > xlogLevels_
Definition: LogCategory.h:298
void setLevelLocked(LogLevel level, bool inherit)
fbstring exceptionStr(const std::exception &e)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
LoggerDB *const db_
Definition: LogCategory.h:280
void handler(int, siginfo_t *, void *)
LogCategory * firstChild_
Definition: LogCategory.h:288
const char * name
Definition: http_parser.c:437
const std::string & getMessage() const
Definition: LogMessage.h:105
LogLevel min
Definition: LogLevel.cpp:30
LogLevel getLevel() const
Definition: LogMessage.h:80
static std::string canonicalize(folly::StringPiece name)
Definition: LogName.cpp:26
const std::string name_
Definition: LogCategory.h:267
void setLevel(LogLevel level, bool inherit=true)
ssize_t writeFull(int fd, const void *buf, size_t count)
Definition: FileUtil.cpp:134
folly::StringPiece getFileName() const
Definition: LogMessage.h:84
LogLevel
Definition: LogLevel.h:38
unsigned int getLineNumber() const
Definition: LogMessage.h:89
constexpr T const & constexpr_clamp(T const &v, T const &lo, T const &hi, Less less)
Definition: ConstexprMath.h:89
void updateHandlers(const std::unordered_map< std::shared_ptr< LogHandler >, std::shared_ptr< LogHandler >> &handlerMap)
void setLevel(folly::StringPiece name, LogLevel level, bool inherit=true)
Definition: LoggerDB.cpp:147
std::vector< std::shared_ptr< LogHandler > > getHandlers() const
LogLevel getEffectiveLevel() const
Definition: LogCategory.h:95
void replaceHandlers(std::vector< std::shared_ptr< LogHandler >> handlers)
std::atomic< LogLevel > effectiveLevel_
Definition: LogCategory.h:246
LogCategory *const parent_
Definition: LogCategory.h:262
folly::Function< void()> child
Definition: AtFork.cpp:35
size_t flushAllHandlers()
Definition: LoggerDB.cpp:551
constexpr bool isLogLevelFatal(LogLevel level)
Definition: LogLevel.h:145
LogCategory * nextSibling_
Definition: LogCategory.h:289
void addHandler(std::shared_ptr< LogHandler > handler)
void updateEffectiveLevel(LogLevel newEffectiveLevel)
void admitMessage(const LogMessage &message) const
Definition: LogCategory.cpp:49
void parentLevelUpdated(LogLevel parentEffectiveLevel)
folly::Function< void()> parent
Definition: AtFork.cpp:34
void registerXlogLevel(std::atomic< LogLevel > *levelPtr)
static void internalWarning(folly::StringPiece file, int lineNumber, Args &&...args) noexcept
Definition: LoggerDB.h:201