2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <type_traits>
22 #include <folly/Conv.h>
23 #include <folly/Format.h>
24 #include <folly/String.h>
25 #include <glog/logging.h>
30 enum class GoogleLoggerStyle { SECONDS, PRETTY };
31 template <GoogleLoggerStyle>
35 * Automatically times a block of code, printing a specified log message on
36 * destruction or whenever the log() method is called. For example:
38 * AutoTimer t("Foo() completed");
40 * t.log("Do work finished");
43 * This would print something like:
44 * "Do work finished in 1.2 seconds"
45 * "Foo() completed in 4.3 seconds"
47 * You can customize what you use as the logger and clock. The logger needs
48 * to have an operator()(StringPiece, double) that gets a message and a duration
49 * (in seconds). The clock needs to model Clock from std::chrono.
51 * The default logger logs usings glog. It only logs if the message is
52 * non-empty, so you can also just use this class for timing, e.g.:
56 * const auto how_long = t.log();
59 class Logger = GoogleLogger<GoogleLoggerStyle::PRETTY>,
60 class Clock = std::chrono::high_resolution_clock>
61 class AutoTimer final {
64 std::string&& msg = "",
65 double minTimetoLog = 0.0,
66 Logger&& logger = Logger())
67 : destructionMessage_(std::move(msg)),
68 minTimeToLog_(minTimetoLog),
69 logger_(std::move(logger)) {}
71 // It doesn't really make sense to copy AutoTimer
72 // Movable to make sure the helper method for creating an AutoTimer works.
73 AutoTimer(const AutoTimer&) = delete;
74 AutoTimer(AutoTimer&&) = default;
75 AutoTimer& operator=(const AutoTimer&) = delete;
76 AutoTimer& operator=(AutoTimer&&) = default;
79 log(destructionMessage_);
82 double log(StringPiece msg = "") {
83 return logImpl(Clock::now(), msg);
86 template <typename... Args>
87 double log(Args&&... args) {
88 auto now = Clock::now();
89 return logImpl(now, to<std::string>(std::forward<Args>(args)...));
92 template <typename... Args>
93 double logFormat(Args&&... args) {
94 auto now = Clock::now();
95 return logImpl(now, format(std::forward<Args>(args)...).str());
99 // We take in the current time so that we don't measure time to call
100 // to<std::string> or format() in the duration.
101 double logImpl(std::chrono::time_point<Clock> now, StringPiece msg) {
103 std::chrono::duration_cast<std::chrono::duration<double>>(now - start_)
105 if (duration >= minTimeToLog_) {
106 logger_(msg, duration);
108 start_ = Clock::now(); // Don't measure logging time
112 const std::string destructionMessage_;
113 std::chrono::time_point<Clock> start_ = Clock::now();
114 double minTimeToLog_;
119 class Logger = GoogleLogger<GoogleLoggerStyle::PRETTY>,
120 class Clock = std::chrono::high_resolution_clock>
122 std::string&& msg = "",
123 double minTimeToLog = 0.0,
124 Logger&& logger = Logger()) {
125 return AutoTimer<Logger, Clock>(
126 std::move(msg), minTimeToLog, std::move(logger));
129 template <GoogleLoggerStyle Style>
130 struct GoogleLogger final {
131 void operator()(StringPiece msg, double sec) const {
135 if (Style == GoogleLoggerStyle::PRETTY) {
136 LOG(INFO) << msg << " in " << prettyPrint(sec, PrettyType::PRETTY_TIME);
138 LOG(INFO) << msg << " in " << sec << " seconds";