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 36 #include <boost/optional/optional.hpp> 37 #include <cJSON.h> 38 #include <memcached/extension.h> 39 #include <memcached/server_api.h> 40 #include <spdlog/logger.h> 41 42 #include <string> 43 44 namespace cb { 45 namespace logger { 46 47 struct LOGGER_PUBLIC_API Config { 48 Config() = default; 49 explicit Config(const cJSON& json); 50 51 bool operator==(const Config& other) const; 52 bool operator!=(const Config& other) const; 53 54 /// The base name of the log files (we'll append: .000000.txt where 55 /// the numbers is a sequence counter. The higher the newer ;) 56 std::string filename; 57 /// 2 MB for the logging queue 58 size_t buffersize = 2048 * 1024; 59 /// 100 MB per cycled file 60 size_t cyclesize = 100 * 1024 * 1024; 61 /// if running in a unit test or not 62 bool unit_test = false; 63 /// Should messages be passed on to the console via stderr 64 bool console = true; 65 /// The default log level to initialize the logger to 66 spdlog::level::level_enum log_level = spdlog::level::level_enum::info; 67 }; 68 69 /** 70 * Initialize the logger. 71 * 72 * The default level for the created logger is set to INFO 73 * 74 * See note about thread safety at the top of the file 75 * 76 * @param logger_settings the configuration for the logger 77 * @return optional error message if something goes wrong 78 */ 79 LOGGER_PUBLIC_API 80 boost::optional<std::string> initialize(const Config& logger_settings); 81 82 /** 83 * Initialize the logger with the blackhole logger object 84 * 85 * This method is intended to be used by unit tests which 86 * don't need any output (but may call methods who tries 87 * to fetch the logger) 88 * 89 * See note about thread safety at the top of the file 90 * 91 * @throws std::bad_alloc 92 * @throws spdlog::spdlog_ex if an error occurs creating the logger 93 * (if it already exists for instance) 94 */ 95 LOGGER_PUBLIC_API 96 void createBlackholeLogger(); 97 98 /** 99 * Initialize the logger with the logger which logs to the console 100 * 101 * See note about thread safety at the top of the file 102 * 103 * @throws std::bad_alloc 104 * @throws spdlog::spdlog_ex if an error occurs creating the logger 105 */ 106 LOGGER_PUBLIC_API 107 void createConsoleLogger(); 108 109 /** 110 * Get the underlying logger object 111 * 112 * See note about thread safety at the top of the file. 113 * 114 * This will return null if a logger has not been 115 * initialized through one of the following: 116 * 117 * - initialize() 118 * - createBlackholeLogger() 119 * - createConsoleLogger() 120 */ 121 LOGGER_PUBLIC_API 122 spdlog::logger* get(); 123 124 /** 125 * Reset the underlying logger object 126 * 127 * See note about thread safety at the top of the file 128 */ 129 LOGGER_PUBLIC_API 130 void reset(); 131 132 LOGGER_PUBLIC_API 133 EXTENSION_LOGGER_DESCRIPTOR& getLoggerDescriptor(); 134 135 /** 136 * Convert a log level as being used by the memcached logger 137 * to spdlog's log levels 138 * 139 * @param sev The memcached severity level 140 * @return The corresponding value in spdlog 141 */ 142 LOGGER_PUBLIC_API 143 spdlog::level::level_enum convertToSpdSeverity(EXTENSION_LOG_LEVEL sev); 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 (severity >= _logger_->level()) { \ 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