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.
19 #include <folly/Conv.h>
20 #include <folly/Format.h>
21 #include <folly/String.h>
22 #include <glog/logging.h>
28 enum class GoogleLoggerStyle { SECONDS, PRETTY };
29 template<GoogleLoggerStyle> struct GoogleLogger;
32 * Automatically times a block of code, printing a specified log message on
33 * destruction or whenever the log() method is called. For example:
35 * AutoTimer t("Foo() completed");
37 * t.log("Do work finished");
40 * This would print something like:
41 * "Do work finished in 1.2 seconds"
42 * "Foo() completed in 4.3 seconds"
44 * You can customize what you use as the logger and clock. The logger needs
45 * to have an operator()(StringPiece, double) that gets a message and a duration
46 * (in seconds). The clock needs to model Clock from std::chrono.
48 * The default logger logs usings glog. It only logs if the message is
49 * non-empty, so you can also just use this class for timing, e.g.:
53 * const auto how_long = t.log();
56 class Logger = GoogleLogger<GoogleLoggerStyle::PRETTY>,
57 class Clock = std::chrono::high_resolution_clock
58 > class AutoTimer final {
60 explicit AutoTimer(StringPiece msg = "")
61 : destructionMessage_(msg.str()),
66 // Automatically generate a log message using to<std::string>. Makes it
67 // easier to do the common case of things like:
68 // AutoTimer t("Processed ", n, " items");
69 template<typename... Args>
70 explicit AutoTimer(Args&&... args)
71 : destructionMessage_(to<std::string>(std::forward<Args>(args)...)),
76 // We don't expose this in the constructor because it creates ambiguity with
77 // the variadic template constructor.
78 void setMinTimeToLog(double t) {
82 // It doesn't really make sense to copy/move an AutoTimer
83 AutoTimer(const AutoTimer&) = delete;
84 AutoTimer(AutoTimer&&) = delete;
85 AutoTimer& operator=(const AutoTimer&) = delete;
86 AutoTimer& operator=(AutoTimer&&) = delete;
89 log(destructionMessage_);
92 double log(StringPiece msg = "") {
93 return logImpl(Clock::now(), msg);
96 template<typename... Args>
97 double log(Args&&... args) {
98 auto now = Clock::now();
99 return logImpl(now, to<std::string>(std::forward<Args>(args)...));
102 template<typename... Args>
103 double logFormat(Args&&... args) {
104 auto now = Clock::now();
105 return logImpl(now, format(std::forward<Args>(args)...).str());
109 // We take in the current time so that we don't measure time to call
110 // to<std::string> or format() in the duration.
111 double logImpl(std::chrono::time_point<Clock> now, StringPiece msg) {
112 double duration = std::chrono::duration_cast<std::chrono::duration<double>>(
115 if (duration >= minTimeToLog_) {
116 Logger()(msg, duration);
118 start_ = Clock::now(); // Don't measure logging time
122 const std::string destructionMessage_;
123 std::chrono::time_point<Clock> start_;
124 double minTimeToLog_;
127 template<GoogleLoggerStyle Style>
128 struct GoogleLogger final {
129 void operator()(StringPiece msg, double sec) const {
133 if (Style == GoogleLoggerStyle::PRETTY) {
134 LOG(INFO) << msg << " in " << prettyPrint(sec, PrettyType::PRETTY_TIME);
136 LOG(INFO) << msg << " in " << sec << " seconds";