proxygen
GlogStyleFormatter.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/Format.h>
19 #include <folly/logging/LogLevel.h>
21 #include <folly/portability/Time.h>
22 
23 namespace {
24 using folly::LogLevel;
25 using folly::StringPiece;
26 
27 StringPiece getGlogLevelName(LogLevel level) {
28  if (level < LogLevel::INFO) {
29  return "VERBOSE";
30  } else if (level < LogLevel::WARN) {
31  return "INFO";
32  } else if (level < LogLevel::ERR) {
33  return "WARNING";
34  } else if (level < LogLevel::CRITICAL) {
35  return "ERROR";
36  } else if (level < LogLevel::DFATAL) {
37  return "CRITICAL";
38  }
39  return "FATAL";
40 }
41 } // namespace
42 
43 namespace folly {
44 
46  const LogMessage& message,
47  const LogCategory* /* handlerCategory */) {
48  // Get the local time info
49  struct tm ltime;
50  auto timeSinceEpoch = message.getTimestamp().time_since_epoch();
51  auto epochSeconds =
52  std::chrono::duration_cast<std::chrono::seconds>(timeSinceEpoch);
53  std::chrono::microseconds usecs =
54  std::chrono::duration_cast<std::chrono::microseconds>(timeSinceEpoch) -
55  epochSeconds;
56  time_t unixTimestamp = epochSeconds.count();
57  if (!localtime_r(&unixTimestamp, &ltime)) {
58  memset(&ltime, 0, sizeof(ltime));
59  }
60 
61  auto basename = message.getFileBaseName();
62  auto headerFormatter = folly::format(
63  "{}{:02d}{:02d} {:02d}:{:02d}:{:02d}.{:06d} {:5d} {}:{}] ",
64  getGlogLevelName(message.getLevel())[0],
65  ltime.tm_mon + 1,
66  ltime.tm_mday,
67  ltime.tm_hour,
68  ltime.tm_min,
69  ltime.tm_sec,
70  usecs.count(),
71  message.getThreadID(),
72  basename,
73  message.getLineNumber());
74 
75  // TODO: Support including thread names and thread context info.
76 
77  // The fixed portion of the header takes up 31 bytes.
78  //
79  // The variable portions that we can't account for here include the line
80  // number and the thread ID (just in case it is larger than 6 digits long).
81  // Here we guess that 40 bytes will be long enough to include room for this.
82  //
83  // If this still isn't long enough the string will grow as necessary, so the
84  // code will still be correct, but just slightly less efficient than if we
85  // had allocated a large enough buffer the first time around.
86  size_t headerLengthGuess = 40 + basename.size();
87 
88  // Format the data into a buffer.
90  StringPiece msgData{message.getMessage()};
91  if (message.containsNewlines()) {
92  // If there are multiple lines in the log message, add a header
93  // before each one.
94  std::string header;
95  header.reserve(headerLengthGuess);
96  headerFormatter.appendTo(header);
97 
98  // Make a guess at how many lines will be in the message, just to make an
99  // initial buffer allocation. If the guess is too small then the string
100  // will reallocate and grow as necessary, it will just be slightly less
101  // efficient than if we had guessed enough space.
102  size_t numLinesGuess = 4;
103  buffer.reserve(((header.size() + 1) * numLinesGuess) + msgData.size());
104 
105  size_t idx = 0;
106  while (true) {
107  auto end = msgData.find('\n', idx);
108  if (end == StringPiece::npos) {
109  end = msgData.size();
110  }
111 
112  buffer.append(header);
113  auto line = msgData.subpiece(idx, end - idx);
114  buffer.append(line.data(), line.size());
115  buffer.push_back('\n');
116 
117  if (end == msgData.size()) {
118  break;
119  }
120  idx = end + 1;
121  }
122  } else {
123  buffer.reserve(headerLengthGuess + msgData.size());
124  headerFormatter.appendTo(buffer);
125  buffer.append(msgData.data(), msgData.size());
126  buffer.push_back('\n');
127  }
128 
129  return buffer;
130 }
131 } // namespace folly
std::vector< uint8_t > buffer(kBufferSize+16)
Definition: test.c:42
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
const std::string & getMessage() const
Definition: LogMessage.h:105
uint64_t getThreadID() const
Definition: LogMessage.h:101
LogLevel getLevel() const
Definition: LogMessage.h:80
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
LogLevel
Definition: LogLevel.h:38
unsigned int getLineNumber() const
Definition: LogMessage.h:89
static const size_type npos
Definition: Range.h:197
std::string formatMessage(const LogMessage &message, const LogCategory *handlerCategory) override
const char * string
Definition: Conv.cpp:212
folly::StringPiece getFileBaseName() const
Definition: LogMessage.cpp:61
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
std::chrono::system_clock::time_point getTimestamp() const
Definition: LogMessage.h:97
Range< const char * > StringPiece
bool containsNewlines() const
Definition: LogMessage.h:117