/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2015-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#pragma once
#include <chrono>
+#include <string>
+#include <type_traits>
+
#include <folly/Conv.h>
#include <folly/Format.h>
+#include <folly/Optional.h>
#include <folly/String.h>
#include <glog/logging.h>
-#include <string>
namespace folly {
// Default logger
enum class GoogleLoggerStyle { SECONDS, PRETTY };
-template<GoogleLoggerStyle> struct GoogleLogger;
+template <GoogleLoggerStyle>
+struct GoogleLogger;
/**
* Automatically times a block of code, printing a specified log message on
* "Foo() completed in 4.3 seconds"
*
* You can customize what you use as the logger and clock. The logger needs
- * to have an operator()(StringPiece, double) that gets a message and a duration
- * (in seconds). The clock needs to model Clock from std::chrono.
+ * to have an operator()(StringPiece, std::chrono::duration<double>) that
+ * gets a message and a duration. The clock needs to model Clock from
+ * std::chrono.
*
* The default logger logs usings glog. It only logs if the message is
* non-empty, so you can also just use this class for timing, e.g.:
* doWork()
* const auto how_long = t.log();
*/
-template<
- class Logger = GoogleLogger<GoogleLoggerStyle::PRETTY>,
- class Clock = std::chrono::high_resolution_clock
-> class AutoTimer final {
-public:
- explicit AutoTimer(StringPiece msg = "")
- : destructionMessage_(msg.str()),
- start_(Clock::now()) {
- }
+template <
+ class Logger = GoogleLogger<GoogleLoggerStyle::PRETTY>,
+ class Clock = std::chrono::high_resolution_clock>
+class AutoTimer final {
+ public:
+ using DoubleSeconds = std::chrono::duration<double>;
- // Automatically generate a log message using to<std::string>. Makes it
- // easier to do the common case of things like:
- // AutoTimer t("Processed ", n, " items");
- template<typename... Args>
- explicit AutoTimer(Args&&... args)
- : destructionMessage_(to<std::string>(std::forward<Args>(args)...)),
- start_(Clock::now()) {
- }
+ explicit AutoTimer(
+ std::string&& msg = "",
+ const DoubleSeconds& minTimetoLog = DoubleSeconds::zero(),
+ Logger&& logger = Logger())
+ : destructionMessage_(std::move(msg)),
+ minTimeToLog_(minTimetoLog),
+ logger_(std::move(logger)) {}
- // It doesn't really make sense to copy/move an AutoTimer
+ // It doesn't really make sense to copy AutoTimer
+ // Movable to make sure the helper method for creating an AutoTimer works.
AutoTimer(const AutoTimer&) = delete;
- AutoTimer(AutoTimer&&) = delete;
+ AutoTimer(AutoTimer&&) = default;
AutoTimer& operator=(const AutoTimer&) = delete;
- AutoTimer& operator=(AutoTimer&&) = delete;
+ AutoTimer& operator=(AutoTimer&&) = default;
~AutoTimer() {
- log(destructionMessage_);
+ if (destructionMessage_) {
+ log(destructionMessage_.value());
+ }
}
- double log(StringPiece msg = "") {
+ DoubleSeconds log(StringPiece msg = "") {
return logImpl(Clock::now(), msg);
}
- template<typename... Args>
- double log(Args&&... args) {
+ template <typename... Args>
+ DoubleSeconds log(Args&&... args) {
auto now = Clock::now();
return logImpl(now, to<std::string>(std::forward<Args>(args)...));
}
- template<typename... Args>
- double logFormat(Args&&... args) {
+ template <typename... Args>
+ DoubleSeconds logFormat(Args&&... args) {
auto now = Clock::now();
return logImpl(now, format(std::forward<Args>(args)...).str());
}
-private:
+ private:
// We take in the current time so that we don't measure time to call
// to<std::string> or format() in the duration.
- double logImpl(std::chrono::time_point<Clock> now, StringPiece msg) {
- double duration = std::chrono::duration_cast<std::chrono::duration<double>>(
- now - start_
- ).count();
- Logger()(msg, duration);
+ DoubleSeconds logImpl(std::chrono::time_point<Clock> now, StringPiece msg) {
+ auto duration = now - start_;
+ if (duration >= minTimeToLog_) {
+ logger_(msg, duration);
+ }
start_ = Clock::now(); // Don't measure logging time
return duration;
}
- const std::string destructionMessage_;
- std::chrono::time_point<Clock> start_;
+ Optional<std::string> destructionMessage_;
+ std::chrono::time_point<Clock> start_ = Clock::now();
+ DoubleSeconds minTimeToLog_;
+ Logger logger_;
};
-template<GoogleLoggerStyle Style>
-struct GoogleLogger {
- void operator()(StringPiece msg, double sec) const {
+template <
+ class Logger = GoogleLogger<GoogleLoggerStyle::PRETTY>,
+ class Clock = std::chrono::high_resolution_clock>
+auto makeAutoTimer(
+ std::string&& msg = "",
+ const std::chrono::duration<double>& minTimeToLog =
+ std::chrono::duration<double>::zero(),
+ Logger&& logger = Logger()) {
+ return AutoTimer<Logger, Clock>(
+ std::move(msg), minTimeToLog, std::move(logger));
+}
+
+template <GoogleLoggerStyle Style>
+struct GoogleLogger final {
+ void operator()(StringPiece msg, const std::chrono::duration<double>& sec)
+ const {
if (msg.empty()) {
return;
}
if (Style == GoogleLoggerStyle::PRETTY) {
- LOG(INFO) << msg << " in " << prettyPrint(sec, PrettyType::PRETTY_TIME);
+ LOG(INFO) << msg << " in "
+ << prettyPrint(sec.count(), PrettyType::PRETTY_TIME);
} else {
- LOG(INFO) << msg << " in " << sec << " seconds";
+ LOG(INFO) << msg << " in " << sec.count() << " seconds";
}
}
};
-
-
-}
+} // namespace folly