1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 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 */ 16 17 #pragma once 18 19 #include <folly/Likely.h> 20 21 #include <atomic> 22 #include <chrono> 23 24 #include <glog/logging.h> 25 26 #ifndef FB_LOG_EVERY_MS 27 /** 28 * Issues a LOG(severity) no more often than every 29 * milliseconds. Example: 30 * 31 * FB_LOG_EVERY_MS(INFO, 10000) << "At least ten seconds passed" 32 * " since you last saw this."; 33 * 34 * The implementation uses for statements to introduce variables in 35 * a nice way that doesn't mess surrounding statements. It is thread 36 * safe. Non-positive intervals will always log. 37 */ 38 #define FB_LOG_EVERY_MS(severity, milli_interval) \ 39 for (decltype(milli_interval) FB_LEM_once = 1, \ 40 FB_LEM_interval = (milli_interval); \ 41 FB_LEM_once;) \ 42 for (::std::chrono::milliseconds::rep FB_LEM_prev, \ 43 FB_LEM_now = FB_LEM_interval <= 0 \ 44 ? 0 \ 45 : ::std::chrono::duration_cast<::std::chrono::milliseconds>( \ 46 ::std::chrono::system_clock::now().time_since_epoch()) \ 47 .count(); \ 48 FB_LEM_once;) \ 49 for (static ::std::atomic<::std::chrono::milliseconds::rep> FB_LEM_hist; \ 50 FB_LEM_once; \ 51 FB_LEM_once = 0) \ 52 if (FB_LEM_interval > 0 && \ 53 (FB_LEM_now - \ 54 (FB_LEM_prev = \ 55 FB_LEM_hist.load(std::memory_order_acquire)) < \ 56 FB_LEM_interval || \ 57 !FB_LEM_hist.compare_exchange_strong(FB_LEM_prev, FB_LEM_now))) { \ 58 } else \ 59 LOG(severity) 60 61 #endif 62 63 /** 64 * Issues a LOG(severity) once. 65 * 66 * FB_LOG_ONCE(ERROR) << "Log this error only once"; 67 * 68 * This macro is thread-safe and does not impact surrounding statements. 69 * 70 * NOTE: A load() is used in the fast-path scenario (steady state) in order to 71 * avoid a locked RMW operation. 72 */ 73 #ifndef FB_LOG_ONCE 74 #define FB_LOG_ONCE(severity) \ 75 for (auto __folly_detail_glog_once = true; __folly_detail_glog_once;) \ 76 for (static ::std::atomic_bool __folly_detail_glog_logged{false}; \ 77 __folly_detail_glog_once; \ 78 __folly_detail_glog_once = false) \ 79 if (FOLLY_LIKELY( \ 80 __folly_detail_glog_logged.load(::std::memory_order_relaxed)) || \ 81 __folly_detail_glog_logged.exchange( \ 82 true, ::std::memory_order_relaxed)) { \ 83 } else \ 84 LOG(severity) 85 #endif 86