1 /* Simple Plugin API 2 * 3 * Copyright © 2018 Wim Taymans 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25 #ifndef SPA_LOG_H 26 #define SPA_LOG_H 27 28 #ifdef __cplusplus 29 extern "C" { 30 #endif 31 32 #include <stdarg.h> 33 34 #include <spa/utils/type.h> 35 #include <spa/utils/defs.h> 36 #include <spa/utils/hook.h> 37 38 /** \defgroup spa_log Log 39 * Logging interface 40 */ 41 42 /** 43 * \addtogroup spa_log 44 * \{ 45 */ 46 47 /** The default log topic. Redefine this in your code to 48 * allow for the spa_log_* macros to work correctly, e.g: 49 * 50 * \code{.c} 51 * struct spa_log_topic *mylogger; 52 * #undef SPA_LOG_TOPIC_DEFAULT 53 * #define SPA_LOG_TOPIC_DEFAULT mylogger 54 * \endcode 55 */ 56 #define SPA_LOG_TOPIC_DEFAULT NULL 57 58 enum spa_log_level { 59 SPA_LOG_LEVEL_NONE = 0, 60 SPA_LOG_LEVEL_ERROR, 61 SPA_LOG_LEVEL_WARN, 62 SPA_LOG_LEVEL_INFO, 63 SPA_LOG_LEVEL_DEBUG, 64 SPA_LOG_LEVEL_TRACE, 65 }; 66 67 /** 68 * The Log interface 69 */ 70 #define SPA_TYPE_INTERFACE_Log SPA_TYPE_INFO_INTERFACE_BASE "Log" 71 72 73 struct spa_log { 74 /** the version of this log. This can be used to expand this 75 * structure in the future */ 76 #define SPA_VERSION_LOG 0 77 struct spa_interface iface; 78 /** 79 * Logging level, everything above this level is not logged 80 */ 81 enum spa_log_level level; 82 }; 83 84 /** 85 * \struct spa_log_topic 86 * 87 * Identifier for a topic. Topics are string-based filters that logically 88 * group messages together. An implementation may decide to filter different 89 * topics on different levels, for example the "protocol" topic may require 90 * debug level TRACE while the "core" topic defaults to debug level INFO. 91 * 92 * spa_log_topics require a spa_log_methods version of 1 or higher. 93 */ 94 struct spa_log_topic { 95 #define SPA_VERSION_LOG_TOPIC 0 96 /** the version of this topic. This can be used to expand this 97 * structure in the future */ 98 uint32_t version; 99 /** The string identifier for the topic */ 100 const char *topic; 101 /** Logging level set for this topic */ 102 enum spa_log_level level; 103 /** False if this topic follows the \ref spa_log level */ 104 bool has_custom_level; 105 }; 106 107 struct spa_log_methods { 108 #define SPA_VERSION_LOG_METHODS 1 109 uint32_t version; 110 /** 111 * Log a message with the given log level. 112 * 113 * \note If compiled with this header, this function is only called 114 * for implementations of version 0. For versions 1 and above, see 115 * logt() instead. 116 * 117 * \param log a spa_log 118 * \param level a spa_log_level 119 * \param file the file name 120 * \param line the line number 121 * \param func the function name 122 * \param fmt printf style format 123 * \param ... format arguments 124 */ 125 void (*log) (void *object, 126 enum spa_log_level level, 127 const char *file, 128 int line, 129 const char *func, 130 const char *fmt, ...) SPA_PRINTF_FUNC(6, 7); 131 132 /** 133 * Log a message with the given log level. 134 * 135 * \note If compiled with this header, this function is only called 136 * for implementations of version 0. For versions 1 and above, see 137 * logtv() instead. 138 * 139 * \param log a spa_log 140 * \param level a spa_log_level 141 * \param file the file name 142 * \param line the line number 143 * \param func the function name 144 * \param fmt printf style format 145 * \param args format arguments 146 */ 147 void (*logv) (void *object, 148 enum spa_log_level level, 149 const char *file, 150 int line, 151 const char *func, 152 const char *fmt, 153 va_list args) SPA_PRINTF_FUNC(6, 0); 154 /** 155 * Log a message with the given log level for the given topic. 156 * 157 * \note Callers that do not use topic-based logging (version 0), the \a 158 * topic is NULL 159 * 160 * \param log a spa_log 161 * \param level a spa_log_level 162 * \param topic the topic for this message, may be NULL 163 * \param file the file name 164 * \param line the line number 165 * \param func the function name 166 * \param fmt printf style format 167 * \param ... format arguments 168 * 169 * \since 1 170 */ 171 void (*logt) (void *object, 172 enum spa_log_level level, 173 const struct spa_log_topic *topic, 174 const char *file, 175 int line, 176 const char *func, 177 const char *fmt, ...) SPA_PRINTF_FUNC(7, 8); 178 179 /** 180 * Log a message with the given log level for the given topic. 181 * 182 * \note For callers that do not use topic-based logging (version 0), 183 * the \a topic is NULL 184 * 185 * \param log a spa_log 186 * \param level a spa_log_level 187 * \param topic the topic for this message, may be NULL 188 * \param file the file name 189 * \param line the line number 190 * \param func the function name 191 * \param fmt printf style format 192 * \param args format arguments 193 * 194 * \since 1 195 */ 196 void (*logtv) (void *object, 197 enum spa_log_level level, 198 const struct spa_log_topic *topic, 199 const char *file, 200 int line, 201 const char *func, 202 const char *fmt, 203 va_list args) SPA_PRINTF_FUNC(7, 0); 204 205 /** 206 * Initializes a \ref spa_log_topic to the correct logging level. 207 * 208 * \since 1 209 */ 210 void (*topic_init) (void *object, struct spa_log_topic *topic); 211 }; 212 213 214 #define SPA_LOG_TOPIC(v, t) \ 215 (struct spa_log_topic){ .version = v, .topic = (t)} 216 217 #define spa_log_topic_init(l, topic) \ 218 do { \ 219 struct spa_log *_l = l; \ 220 if (SPA_LIKELY(_l)) { \ 221 struct spa_interface *_if = &_l->iface; \ 222 spa_interface_call(_if, struct spa_log_methods, \ 223 topic_init, 1, topic); \ 224 } \ 225 } while(0) 226 227 /* Unused, left for backwards compat */ 228 #define spa_log_level_enabled(l,lev) ((l) && (l)->level >= (lev)) 229 230 #define spa_log_level_topic_enabled(l,topic,lev) \ 231 ({ \ 232 struct spa_log *_log = l; \ 233 enum spa_log_level _lev = _log ? _log->level : SPA_LOG_LEVEL_NONE; \ 234 struct spa_log_topic *_t = (struct spa_log_topic *)topic; \ 235 if (_t && _t->has_custom_level) \ 236 _lev = _t->level; \ 237 _lev >= lev; \ 238 }) 239 240 /* Transparently calls to version 0 log if v1 is not supported */ 241 #define spa_log_logt(l,lev,topic,...) \ 242 ({ \ 243 struct spa_log *_l = l; \ 244 struct spa_interface *_if = &_l->iface; \ 245 if (SPA_UNLIKELY(spa_log_level_topic_enabled(_l, topic, lev))) { \ 246 if (!spa_interface_call(_if, \ 247 struct spa_log_methods, logt, 1, \ 248 lev, topic, \ 249 __VA_ARGS__)) \ 250 spa_interface_call(_if, \ 251 struct spa_log_methods, log, 0, \ 252 lev, __VA_ARGS__); \ 253 } \ 254 }) 255 256 /* Transparently calls to version 0 logv if v1 is not supported */ 257 #define spa_log_logtv(l,lev,topic,...) \ 258 ({ \ 259 struct spa_log *_l = l; \ 260 struct spa_interface *_if = &_l->iface; \ 261 if (SPA_UNLIKELY(spa_log_level_topic_enabled(_l, topic, lev))) { \ 262 if (!spa_interface_call(_if, \ 263 struct spa_log_methods, logtv, 1, \ 264 lev, topic, \ 265 __VA_ARGS__)) \ 266 spa_interface_call(_if, \ 267 struct spa_log_methods, logv, 0, \ 268 lev, __VA_ARGS__); \ 269 } \ 270 }) 271 272 #define spa_log_log(l,lev,...) \ 273 spa_log_logt(l,lev,SPA_LOG_TOPIC_DEFAULT,__VA_ARGS__) 274 275 #define spa_log_logv(l,lev,...) \ 276 spa_log_logtv(l,lev,SPA_LOG_TOPIC_DEFAULT,__VA_ARGS__) 277 278 #define spa_log_error(l,...) spa_log_log(l,SPA_LOG_LEVEL_ERROR,__FILE__,__LINE__,__func__,__VA_ARGS__) 279 #define spa_log_warn(l,...) spa_log_log(l,SPA_LOG_LEVEL_WARN,__FILE__,__LINE__,__func__,__VA_ARGS__) 280 #define spa_log_info(l,...) spa_log_log(l,SPA_LOG_LEVEL_INFO,__FILE__,__LINE__,__func__,__VA_ARGS__) 281 #define spa_log_debug(l,...) spa_log_log(l,SPA_LOG_LEVEL_DEBUG,__FILE__,__LINE__,__func__,__VA_ARGS__) 282 #define spa_log_trace(l,...) spa_log_log(l,SPA_LOG_LEVEL_TRACE,__FILE__,__LINE__,__func__,__VA_ARGS__) 283 284 #define spa_logt_error(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_ERROR,t,__FILE__,__LINE__,__func__,__VA_ARGS__) 285 #define spa_logt_warn(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_WARN,t,__FILE__,__LINE__,__func__,__VA_ARGS__) 286 #define spa_logt_info(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_INFO,t,__FILE__,__LINE__,__func__,__VA_ARGS__) 287 #define spa_logt_debug(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_DEBUG,t,__FILE__,__LINE__,__func__,__VA_ARGS__) 288 #define spa_logt_trace(l,t,...) spa_log_logt(l,SPA_LOG_LEVEL_TRACE,t,__FILE__,__LINE__,__func__,__VA_ARGS__) 289 290 #ifndef FASTPATH 291 #define spa_log_trace_fp(l,...) spa_log_log(l,SPA_LOG_LEVEL_TRACE,__FILE__,__LINE__,__func__,__VA_ARGS__) 292 #else 293 #define spa_log_trace_fp(l,...) 294 #endif 295 296 /** \fn spa_log_error */ 297 298 /** keys can be given when initializing the logger handle */ 299 #define SPA_KEY_LOG_LEVEL "log.level" /**< the default log level */ 300 #define SPA_KEY_LOG_COLORS "log.colors" /**< enable colors in the logger */ 301 #define SPA_KEY_LOG_FILE "log.file" /**< log to the specified file instead of 302 * stderr. */ 303 #define SPA_KEY_LOG_TIMESTAMP "log.timestamp" /**< log timestamps */ 304 #define SPA_KEY_LOG_LINE "log.line" /**< log file and line numbers */ 305 #define SPA_KEY_LOG_PATTERNS "log.patterns" /**< Spa:String:JSON array of [ {"pattern" : level}, ... ] */ 306 307 /** 308 * \} 309 */ 310 311 #ifdef __cplusplus 312 } /* extern "C" */ 313 #endif 314 #endif /* SPA_LOG_H */ 315