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