logging: set the thread name for the AsyncFileWriter thread
[folly.git] / folly / experimental / AutoTimer.h
index dfe2bcfecf005044eefef6c192dae03008ec5cdb..545c3be7649319e4dfc14da3f7c5df21dc9c8aa7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 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
@@ -42,8 +46,9 @@ template<GoogleLoggerStyle> struct GoogleLogger;
  *   "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.:
@@ -52,80 +57,93 @@ template<GoogleLoggerStyle> struct GoogleLogger;
  *   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)...));
+    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