1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2018 Couchbase, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* 19 * A note on the thread safety of the logger API: 20 * 21 * The API is thread safe unless the underlying logger object is changed 22 * during runtime. This means some methods can only be safely called if the 23 * caller guarantees no other threads exist and/or are calling the logging 24 * functions. 25 * 26 * The caveat being we should not change the underlying logger object during 27 * run-time, the exception to this is during the initial memcached startup, 28 * where we are running in a single thread at the point we switch from console 29 * logging to file logging. 30 */ 31 32 #pragma once 33 34 #include <logger/visibility.h> 35 #include <spdlog/fmt/ostr.h> 36 #include <spdlog/logger.h> 37 38 #include <boost/optional/optional_fwd.hpp> 39 40 #include <string> 41 42 namespace cb { 43 namespace logger { 44 45 struct Config; 46 47 /** 48 * Initialize the logger. 49 * 50 * The default level for the created logger is set to INFO 51 * 52 * See note about thread safety at the top of the file 53 * 54 * @param logger_settings the configuration for the logger 55 * @return optional error message if something goes wrong 56 */ 57 LOGGER_PUBLIC_API 58 boost::optional<std::string> initialize(const Config& logger_settings); 59 60 /** 61 * Initialize the logger with the blackhole logger object 62 * 63 * This method is intended to be used by unit tests which 64 * don't need any output (but may call methods who tries 65 * to fetch the logger) 66 * 67 * See note about thread safety at the top of the file 68 * 69 * @throws std::bad_alloc 70 * @throws spdlog::spdlog_ex if an error occurs creating the logger 71 * (if it already exists for instance) 72 */ 73 LOGGER_PUBLIC_API 74 void createBlackholeLogger(); 75 76 /** 77 * Initialize the logger with the logger which logs to the console 78 * 79 * See note about thread safety at the top of the file 80 * 81 * @throws std::bad_alloc 82 * @throws spdlog::spdlog_ex if an error occurs creating the logger 83 */ 84 LOGGER_PUBLIC_API 85 void createConsoleLogger(); 86 87 /** 88 * Get the underlying logger object 89 * 90 * See note about thread safety at the top of the file. 91 * 92 * This will return null if a logger has not been 93 * initialized through one of the following: 94 * 95 * - initialize() 96 * - createBlackholeLogger() 97 * - createConsoleLogger() 98 */ 99 LOGGER_PUBLIC_API 100 spdlog::logger* get(); 101 102 /** 103 * Reset the underlying logger object 104 * 105 * See note about thread safety at the top of the file 106 */ 107 LOGGER_PUBLIC_API 108 void reset(); 109 110 /** 111 * Engines that create their own instances of an spdlogger should register 112 * the logger here to ensure that the verbosity of the logger is updated when 113 * memcached receives a request to update verbosity 114 * 115 * @param l spdlogger instance 116 */ 117 LOGGER_PUBLIC_API 118 void registerSpdLogger(std::shared_ptr<spdlog::logger> l); 119 120 /** 121 * Engines that create their own instances of an spdlogger should unregister 122 * the logger here to ensure that resources can be freed when their loggers 123 * go out of scope, or unsubscribe from runtime verbosity changes 124 * 125 * @param n The name of the spdlogger 126 */ 127 LOGGER_PUBLIC_API 128 void unregisterSpdLogger(const std::string& n); 129 130 /** 131 * Check the log level of all spdLoggers is equal to the given level 132 * @param log severity level 133 * @return true if all registered loggers have the specified severity level 134 */ 135 LOGGER_PUBLIC_API 136 bool checkLogLevels(spdlog::level::level_enum level); 137 138 /** 139 * Set the log level of all registered spdLoggers 140 * @param log severity level 141 */ 142 LOGGER_PUBLIC_API 143 void setLogLevels(spdlog::level::level_enum level); 144 145 /** 146 * Tell the logger to flush its buffers 147 */ 148 LOGGER_PUBLIC_API 149 void flush(); 150 151 /** 152 * Tell the logger to shut down (flush buffers) and release _ALL_ 153 * loggers (you'd need to create new loggers after this method) 154 */ 155 LOGGER_PUBLIC_API 156 void shutdown(); 157 158 /** 159 * @return whether or not the logger has been initialized 160 */ 161 LOGGER_PUBLIC_API const bool isInitialized(); 162 163 } // namespace logger 164 } // namespace cb 165 166 #define CB_LOG_ENTRY(severity, ...) \ 167 do { \ 168 auto _logger_ = cb::logger::get(); \ 169 if (_logger_ && _logger_->should_log(severity)) { \ 170 _logger_->log(severity, __VA_ARGS__); \ 171 } \ 172 } while (false) 173 174 #define LOG_TRACE(...) \ 175 CB_LOG_ENTRY(spdlog::level::level_enum::trace, __VA_ARGS__) 176 #define LOG_DEBUG(...) \ 177 CB_LOG_ENTRY(spdlog::level::level_enum::debug, __VA_ARGS__) 178 #define LOG_INFO(...) CB_LOG_ENTRY(spdlog::level::level_enum::info, __VA_ARGS__) 179 #define LOG_WARNING(...) \ 180 CB_LOG_ENTRY(spdlog::level::level_enum::warn, __VA_ARGS__) 181 #define LOG_ERROR(...) CB_LOG_ENTRY(spdlog::level::level_enum::err, __VA_ARGS__) 182 #define LOG_CRITICAL(...) \ 183 CB_LOG_ENTRY(spdlog::level::level_enum::critical, __VA_ARGS__) 184