1 /* PipeWire
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 #include <limits.h>
26 #include <fnmatch.h>
27
28 #include <spa/support/log-impl.h>
29
30 #include <spa/pod/pod.h>
31 #include <spa/debug/types.h>
32 #include <spa/pod/iter.h>
33 #include <spa/utils/list.h>
34
35 #include <pipewire/log.h>
36 #include <pipewire/private.h>
37
38 SPA_LOG_IMPL(default_log);
39
40 #define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_WARN
41
42 SPA_EXPORT
43 enum spa_log_level pw_log_level = DEFAULT_LOG_LEVEL;
44
45 static struct spa_log *global_log = &default_log.log;
46
47 SPA_EXPORT
48 struct spa_log_topic *PW_LOG_TOPIC_DEFAULT;
49
50 PW_LOG_TOPIC_STATIC(log_topic, "pw.log"); /* log topic for this file here */
51 PW_LOG_TOPIC(log_buffers, "pw.buffers");
52 PW_LOG_TOPIC(log_client, "pw.client");
53 PW_LOG_TOPIC(log_conf, "pw.conf");
54 PW_LOG_TOPIC(log_context, "pw.context");
55 PW_LOG_TOPIC(log_core, "pw.core");
56 PW_LOG_TOPIC(log_data_loop, "pw.data-loop");
57 PW_LOG_TOPIC(log_device, "pw.device");
58 PW_LOG_TOPIC(log_factory, "pw.factory");
59 PW_LOG_TOPIC(log_filter, "pw.filter");
60 PW_LOG_TOPIC(log_global, "pw.global");
61 PW_LOG_TOPIC(log_link, "pw.link");
62 PW_LOG_TOPIC(log_loop, "pw.loop");
63 PW_LOG_TOPIC(log_main_loop, "pw.main-loop");
64 PW_LOG_TOPIC(log_mem, "pw.mem");
65 PW_LOG_TOPIC(log_metadata, "pw.metadata");
66 PW_LOG_TOPIC(log_module, "pw.module");
67 PW_LOG_TOPIC(log_node, "pw.node");
68 PW_LOG_TOPIC(log_port, "pw.port");
69 PW_LOG_TOPIC(log_properties, "pw.props");
70 PW_LOG_TOPIC(log_protocol, "pw.protocol");
71 PW_LOG_TOPIC(log_proxy, "pw.proxy");
72 PW_LOG_TOPIC(log_resource, "pw.resource");
73 PW_LOG_TOPIC(log_stream, "pw.stream");
74 PW_LOG_TOPIC(log_thread_loop, "pw.thread-loop");
75 PW_LOG_TOPIC(log_work_queue, "pw.work-queue");
76
77 PW_LOG_TOPIC(PW_LOG_TOPIC_DEFAULT, "default");
78
79 /** Set the global log interface
80 * \param log the global log to set
81 */
82 SPA_EXPORT
pw_log_set(struct spa_log * log)83 void pw_log_set(struct spa_log *log)
84 {
85 global_log = log ? log : &default_log.log;
86 global_log->level = pw_log_level;
87 }
88
pw_log_is_default(void)89 bool pw_log_is_default(void)
90 {
91 return global_log == &default_log.log;
92 }
93
94 /** Get the global log interface
95 * \return the global log
96 */
97 SPA_EXPORT
pw_log_get(void)98 struct spa_log *pw_log_get(void)
99 {
100 return global_log;
101 }
102
103 /** Set the global log level
104 * \param level the new log level
105 */
106 SPA_EXPORT
pw_log_set_level(enum spa_log_level level)107 void pw_log_set_level(enum spa_log_level level)
108 {
109 pw_log_level = level;
110 global_log->level = level;
111 }
112
113 /** Log a message for the given topic
114 * \param level the log level
115 * \param topic the topic
116 * \param file the file this message originated from
117 * \param line the line number
118 * \param func the function
119 * \param fmt the printf style format
120 * \param ... printf style arguments to log
121 *
122 */
123 SPA_EXPORT
124 void
pw_log_logt(enum spa_log_level level,const struct spa_log_topic * topic,const char * file,int line,const char * func,const char * fmt,...)125 pw_log_logt(enum spa_log_level level,
126 const struct spa_log_topic *topic,
127 const char *file,
128 int line,
129 const char *func,
130 const char *fmt, ...)
131 {
132 if (SPA_UNLIKELY(pw_log_topic_enabled(level, topic))) {
133 va_list args;
134 va_start(args, fmt);
135 spa_log_logtv(global_log, level, topic, file, line, func, fmt, args);
136 va_end(args);
137 }
138 }
139
140 /** Log a message for the given topic with va_list
141 * \param level the log level
142 * \param topic the topic
143 * \param file the file this message originated from
144 * \param line the line number
145 * \param func the function
146 * \param fmt the printf style format
147 * \param args a va_list of arguments
148 *
149 */
150 SPA_EXPORT
151 void
pw_log_logtv(enum spa_log_level level,const struct spa_log_topic * topic,const char * file,int line,const char * func,const char * fmt,va_list args)152 pw_log_logtv(enum spa_log_level level,
153 const struct spa_log_topic *topic,
154 const char *file,
155 int line,
156 const char *func,
157 const char *fmt,
158 va_list args)
159 {
160 spa_log_logtv(global_log, level, topic, file, line, func, fmt, args);
161 }
162
163
164 /** Log a message for the default topic with va_list
165 * \param level the log level
166 * \param file the file this message originated from
167 * \param line the line number
168 * \param func the function
169 * \param fmt the printf style format
170 * \param args a va_list of arguments
171 *
172 */
173 SPA_EXPORT
174 void
pw_log_logv(enum spa_log_level level,const char * file,int line,const char * func,const char * fmt,va_list args)175 pw_log_logv(enum spa_log_level level,
176 const char *file,
177 int line,
178 const char *func,
179 const char *fmt,
180 va_list args)
181 {
182 pw_log_logtv(level, PW_LOG_TOPIC_DEFAULT, file, line, func, fmt, args);
183 }
184
185 /** Log a message for the default topic
186 * \param level the log level
187 * \param file the file this message originated from
188 * \param line the line number
189 * \param func the function
190 * \param fmt the printf style format
191 * \param ... printf style arguments to log
192 *
193 */
194 SPA_EXPORT
195 void
pw_log_log(enum spa_log_level level,const char * file,int line,const char * func,const char * fmt,...)196 pw_log_log(enum spa_log_level level,
197 const char *file,
198 int line,
199 const char *func,
200 const char *fmt, ...)
201 {
202 va_list args;
203 va_start(args, fmt);
204 pw_log_logtv(level, PW_LOG_TOPIC_DEFAULT, file, line, func, fmt, args);
205 va_end(args);
206 }
207
208 /** \fn void pw_log_error (const char *format, ...)
209 * Log an error message
210 * \param format a printf style format
211 * \param ... printf style arguments
212 */
213 /** \fn void pw_log_warn (const char *format, ...)
214 * Log a warning message
215 * \param format a printf style format
216 * \param ... printf style arguments
217 */
218 /** \fn void pw_log_info (const char *format, ...)
219 * Log an info message
220 * \param format a printf style format
221 * \param ... printf style arguments
222 */
223 /** \fn void pw_log_debug (const char *format, ...)
224 * Log a debug message
225 * \param format a printf style format
226 * \param ... printf style arguments
227 */
228 /** \fn void pw_log_trace (const char *format, ...)
229 * Log a trace message. Trace messages may be generated from
230 * \param format a printf style format
231 * \param ... printf style arguments
232 * realtime threads
233 */
234
235 struct log_ctx {
236 enum spa_log_level level;
237 const char *file;
238 int line;
239 const char *func;
240 };
241
242 #define _log(_c,fmt,...) pw_log_log(_c->level, _c->file, _c->line, _c->func, \
243 "%*s" fmt, indent, "", ## __VA_ARGS__)
244
245 static inline int
log_pod_value(struct log_ctx * ctx,int indent,const struct spa_type_info * info,uint32_t type,void * body,uint32_t size)246 log_pod_value(struct log_ctx *ctx, int indent, const struct spa_type_info *info,
247 uint32_t type, void *body, uint32_t size)
248 {
249 switch (type) {
250 case SPA_TYPE_Bool:
251 _log(ctx, "Bool %s", (*(int32_t *) body) ? "true" : "false");
252 break;
253 case SPA_TYPE_Id:
254 _log(ctx, "Id %-8d (%s)", *(int32_t *) body,
255 spa_debug_type_find_name(info, *(int32_t *) body));
256 break;
257 case SPA_TYPE_Int:
258 _log(ctx, "Int %d", *(int32_t *) body);
259 break;
260 case SPA_TYPE_Long:
261 _log(ctx, "Long %" PRIi64 "", *(int64_t *) body);
262 break;
263 case SPA_TYPE_Float:
264 _log(ctx, "Float %f", *(float *) body);
265 break;
266 case SPA_TYPE_Double:
267 _log(ctx, "Double %f", *(double *) body);
268 break;
269 case SPA_TYPE_String:
270 _log(ctx, "String \"%s\"", (char *) body);
271 break;
272 case SPA_TYPE_Fd:
273 _log(ctx, "Fd %d", *(int *) body);
274 break;
275 case SPA_TYPE_Pointer:
276 {
277 struct spa_pod_pointer_body *b = (struct spa_pod_pointer_body *)body;
278 _log(ctx, "Pointer %s %p",
279 spa_debug_type_find_name(SPA_TYPE_ROOT, b->type), b->value);
280 break;
281 }
282 case SPA_TYPE_Rectangle:
283 {
284 struct spa_rectangle *r = (struct spa_rectangle *)body;
285 _log(ctx, "Rectangle %dx%d", r->width, r->height);
286 break;
287 }
288 case SPA_TYPE_Fraction:
289 {
290 struct spa_fraction *f = (struct spa_fraction *)body;
291 _log(ctx, "Fraction %d/%d", f->num, f->denom);
292 break;
293 }
294 case SPA_TYPE_Bitmap:
295 _log(ctx, "Bitmap");
296 break;
297 case SPA_TYPE_Array:
298 {
299 struct spa_pod_array_body *b = (struct spa_pod_array_body *)body;
300 void *p;
301 const struct spa_type_info *ti = spa_debug_type_find(SPA_TYPE_ROOT, b->child.type);
302
303 _log(ctx, "Array: child.size %d, child.type %s", b->child.size,
304 ti ? ti->name : "unknown");
305
306 SPA_POD_ARRAY_BODY_FOREACH(b, size, p)
307 log_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size);
308 break;
309 }
310 case SPA_TYPE_Choice:
311 {
312 struct spa_pod_choice_body *b = (struct spa_pod_choice_body *)body;
313 void *p;
314 const struct spa_type_info *ti = spa_debug_type_find(spa_type_choice, b->type);
315
316 _log(ctx, "Choice: type %s, flags %08x %d %d",
317 ti ? ti->name : "unknown", b->flags, size, b->child.size);
318
319 SPA_POD_CHOICE_BODY_FOREACH(b, size, p)
320 log_pod_value(ctx, indent + 2, info, b->child.type, p, b->child.size);
321 break;
322 }
323 case SPA_TYPE_Struct:
324 {
325 struct spa_pod *b = (struct spa_pod *)body, *p;
326 _log(ctx, "Struct: size %d", size);
327 SPA_POD_FOREACH(b, size, p)
328 log_pod_value(ctx, indent + 2, info, p->type, SPA_POD_BODY(p), p->size);
329 break;
330 }
331 case SPA_TYPE_Object:
332 {
333 struct spa_pod_object_body *b = (struct spa_pod_object_body *)body;
334 struct spa_pod_prop *p;
335 const struct spa_type_info *ti, *ii;
336
337 ti = spa_debug_type_find(info, b->type);
338 ii = ti ? spa_debug_type_find(ti->values, 0) : NULL;
339 ii = ii ? spa_debug_type_find(ii->values, b->id) : NULL;
340
341 _log(ctx, "Object: size %d, type %s (%d), id %s (%d)", size,
342 ti ? ti->name : "unknown", b->type, ii ? ii->name : "unknown", b->id);
343
344 info = ti ? ti->values : info;
345
346 indent += 2;
347 SPA_POD_OBJECT_BODY_FOREACH(b, size, p) {
348 ii = spa_debug_type_find(info, p->key);
349
350 _log(ctx, "Prop: key %s (%d), flags %08x",
351 ii ? ii->name : "unknown", p->key, p->flags);
352
353 log_pod_value(ctx, indent + 2, ii ? ii->values : NULL,
354 p->value.type,
355 SPA_POD_CONTENTS(struct spa_pod_prop, p),
356 p->value.size);
357 }
358 indent -= 2;
359 break;
360 }
361 case SPA_TYPE_Sequence:
362 {
363 struct spa_pod_sequence_body *b = (struct spa_pod_sequence_body *)body;
364 const struct spa_type_info *ti, *ii;
365 struct spa_pod_control *c;
366
367 ti = spa_debug_type_find(info, b->unit);
368
369 _log(ctx, "%*s" "Sequence: size %d, unit %s", indent, "", size,
370 ti ? ti->name : "unknown");
371
372 indent +=2;
373 SPA_POD_SEQUENCE_BODY_FOREACH(b, size, c) {
374 ii = spa_debug_type_find(spa_type_control, c->type);
375
376 _log(ctx, "Control: offset %d, type %s",
377 c->offset, ii ? ii->name : "unknown");
378
379 log_pod_value(ctx, indent + 2, ii ? ii->values : NULL,
380 c->value.type,
381 SPA_POD_CONTENTS(struct spa_pod_control, c),
382 c->value.size);
383 }
384 indent -=2;
385 break;
386 }
387 case SPA_TYPE_Bytes:
388 _log(ctx, "Bytes");
389 break;
390 case SPA_TYPE_None:
391 _log(ctx, "None");
392 break;
393 default:
394 _log(ctx, "unhandled POD type %d", type);
395 break;
396 }
397 return 0;
398 }
399
pw_log_log_object(enum spa_log_level level,const char * file,int line,const char * func,uint32_t flags,const void * object)400 void pw_log_log_object(enum spa_log_level level,
401 const char *file,
402 int line,
403 const char *func,
404 uint32_t flags, const void *object)
405 {
406 struct log_ctx ctx = { level, file, 0, func, };
407 if (flags & PW_LOG_OBJECT_POD) {
408 const struct spa_pod *pod = object;
409 if (pod == NULL) {
410 pw_log_log(level, file, line, func, "NULL");
411 } else {
412 log_pod_value(&ctx, 0, SPA_TYPE_ROOT,
413 SPA_POD_TYPE(pod),
414 SPA_POD_BODY(pod),
415 SPA_POD_BODY_SIZE(pod));
416 }
417 }
418 }
419
420 SPA_EXPORT
421 void
_pw_log_topic_new(struct spa_log_topic * topic)422 _pw_log_topic_new(struct spa_log_topic *topic)
423 {
424 spa_log_topic_init(global_log, topic);
425 }
426
427 void
pw_log_init(void)428 pw_log_init(void)
429 {
430 PW_LOG_TOPIC_INIT(PW_LOG_TOPIC_DEFAULT);
431 PW_LOG_TOPIC_INIT(log_buffers);
432 PW_LOG_TOPIC_INIT(log_client);
433 PW_LOG_TOPIC_INIT(log_conf);
434 PW_LOG_TOPIC_INIT(log_context);
435 PW_LOG_TOPIC_INIT(log_core);
436 PW_LOG_TOPIC_INIT(log_data_loop);
437 PW_LOG_TOPIC_INIT(log_device);
438 PW_LOG_TOPIC_INIT(log_factory);
439 PW_LOG_TOPIC_INIT(log_filter);
440 PW_LOG_TOPIC_INIT(log_global);
441 PW_LOG_TOPIC_INIT(log_link);
442 PW_LOG_TOPIC_INIT(log_loop);
443 PW_LOG_TOPIC_INIT(log_main_loop);
444 PW_LOG_TOPIC_INIT(log_mem);
445 PW_LOG_TOPIC_INIT(log_metadata);
446 PW_LOG_TOPIC_INIT(log_module);
447 PW_LOG_TOPIC_INIT(log_node);
448 PW_LOG_TOPIC_INIT(log_port);
449 PW_LOG_TOPIC_INIT(log_properties);
450 PW_LOG_TOPIC_INIT(log_protocol);
451 PW_LOG_TOPIC_INIT(log_proxy);
452 PW_LOG_TOPIC_INIT(log_resource);
453 PW_LOG_TOPIC_INIT(log_stream);
454 PW_LOG_TOPIC_INIT(log_thread_loop);
455 PW_LOG_TOPIC_INIT(log_topic);
456 PW_LOG_TOPIC_INIT(log_work_queue);
457 }
458