blob: caeaa4a89b26913562031e2761d969f4a745bd26 [file] [log] [blame]
Pekka Paalanena5630ea2017-10-12 13:13:42 +02001/*
2 * Copyright © 2017 Pekka Paalanen <pq@iki.fi>
3 * Copyright © 2018 Zodiac Inflight Innovations
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27#include "config.h"
28
Marius Vladc901e892019-06-21 22:49:18 +030029#include <libweston/weston-log.h>
Pekka Paalanenc232f8d2019-04-05 16:09:45 +030030#include "shared/helpers.h"
Pekka Paalanen3d5d9472019-03-28 16:28:47 +020031#include <libweston/libweston.h>
Pekka Paalanena5630ea2017-10-12 13:13:42 +020032
Marius Vlade0a858a2019-06-25 12:48:56 +030033#include "weston-log-internal.h"
Pekka Paalanena5630ea2017-10-12 13:13:42 +020034#include "weston-debug-server-protocol.h"
35
36#include <assert.h>
37#include <unistd.h>
38#include <stdarg.h>
39#include <string.h>
40#include <errno.h>
41#include <sys/time.h>
42
Marius Vlad8b8b8032019-06-27 18:34:03 +030043/**
44 * @defgroup log Public Logging/Debugging API
45 * @defgroup internal-log Private/Internal Logging/Debugging API
46 * @defgroup debug-protocol weston-debug protocol specific
47 */
48
Marius Vlad3d7d9782019-04-17 12:35:38 +030049/** Main weston-log context
Pekka Paalanena5630ea2017-10-12 13:13:42 +020050 *
Marius Vlade0a858a2019-06-25 12:48:56 +030051 * One per weston_compositor. Stores list of scopes created and a list pending
52 * subscriptions.
Pekka Paalanena5630ea2017-10-12 13:13:42 +020053 *
Marius Vlade0a858a2019-06-25 12:48:56 +030054 * A pending subscription is a subscription to a scope which hasn't been
55 * created. When the scope is finally created the pending subscription will be
56 * removed from the pending subscription list, but not before was added in the
57 * scope's subscription list and that of the subscriber list.
58 *
59 * Pending subscriptions only make sense for other types of streams, other than
60 * those created by weston-debug protocol. In the case of the weston-debug
61 * protocol, the subscription processes is done automatically whenever a client
62 * connects and subscribes to a scope which was previously advertised by the
63 * compositor.
64 *
Marius Vlad8b8b8032019-06-27 18:34:03 +030065 * @ingroup internal-log
Pekka Paalanena5630ea2017-10-12 13:13:42 +020066 */
Marius Vlad3d7d9782019-04-17 12:35:38 +030067struct weston_log_context {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020068 struct wl_global *global;
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -030069 struct wl_listener compositor_destroy_listener;
Marius Vlad5d5e3352019-04-17 13:05:38 +030070 struct wl_list scope_list; /**< weston_log_scope::compositor_link */
Marius Vlade0a858a2019-06-25 12:48:56 +030071 struct wl_list pending_subscription_list; /**< weston_log_subscription::source_link */
Pekka Paalanena5630ea2017-10-12 13:13:42 +020072};
73
Marius Vlad5d5e3352019-04-17 13:05:38 +030074/** weston-log message scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +020075 *
Marius Vlad7e4db952019-04-17 13:47:06 +030076 * This is used for scoping logging/debugging messages. Clients can subscribe
77 * to only the scopes they are interested in. A scope is identified by its name
Pekka Paalanena5630ea2017-10-12 13:13:42 +020078 * (also referred to as debug stream name).
Marius Vlad8b8b8032019-06-27 18:34:03 +030079 *
80 * @ingroup log
Pekka Paalanena5630ea2017-10-12 13:13:42 +020081 */
Marius Vlad5d5e3352019-04-17 13:05:38 +030082struct weston_log_scope {
Pekka Paalanena5630ea2017-10-12 13:13:42 +020083 char *name;
84 char *desc;
Marius Vlad0c7beb02019-07-25 11:46:44 +030085 weston_log_scope_cb new_subscription;
Marius Vlad9bb1c3a2019-07-29 12:02:47 +030086 weston_log_scope_cb destroy_subscription;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020087 void *user_data;
Pekka Paalanena5630ea2017-10-12 13:13:42 +020088 struct wl_list compositor_link;
Marius Vlade0a858a2019-06-25 12:48:56 +030089 struct wl_list subscription_list; /**< weston_log_subscription::source_link */
Pekka Paalanena5630ea2017-10-12 13:13:42 +020090};
91
Marius Vlade0a858a2019-06-25 12:48:56 +030092/** Ties a subscriber to a scope
93 *
94 * A subscription is created each time we'd want to subscribe to a scope. From
95 * the stream type we can retrieve the subscriber and from the subscriber we
96 * reach each of the streams callbacks. See also weston_log_subscriber object.
97 *
98 * When a subscription has been created we store it in the scope's subscription
99 * list and in the subscriber's subscription list. The subscription might be a
100 * pending subscription until the scope for which there's was a subscribe has
101 * been created. The scope creation will take of looking through the pending
102 * subscription list.
103 *
104 * A subscription can reached from a subscriber subscription list by using the
105 * streams base class.
106 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300107 * @ingroup internal-log
Marius Vlade0a858a2019-06-25 12:48:56 +0300108 */
109struct weston_log_subscription {
110 struct weston_log_subscriber *owner;
111 struct wl_list owner_link; /**< weston_log_subscriber::subscription_list */
112
113 char *scope_name;
114 struct weston_log_scope *source;
115 struct wl_list source_link; /**< weston_log_scope::subscription_list or
116 weston_log_context::pending_subscription_list */
Marius Vlad410d0bc2019-07-29 12:05:29 +0300117
118 void *data;
Marius Vlade0a858a2019-06-25 12:48:56 +0300119};
120
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300121static struct weston_log_subscription *
122find_pending_subscription(struct weston_log_context *log_ctx,
123 const char *scope_name)
124{
125 struct weston_log_subscription *sub;
126
127 wl_list_for_each(sub, &log_ctx->pending_subscription_list, source_link)
Marius Vladf68ee072019-11-05 17:08:17 +0200128 if (!strcmp(sub->scope_name, scope_name))
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300129 return sub;
130
131 return NULL;
132}
133
134/** Create a pending subscription and add it the list of pending subscriptions
135 *
136 * @param owner a subscriber represented by weston_log_subscriber object
137 * @param scope_name the name of the scope (which we don't have in the list of scopes)
138 * @param log_ctx the logging context used to add the pending subscription
139 *
140 * @memberof weston_log_subscription
141 */
142static void
143weston_log_subscription_create_pending(struct weston_log_subscriber *owner,
144 const char *scope_name,
145 struct weston_log_context *log_ctx)
146{
147 assert(owner);
148 assert(scope_name);
149 struct weston_log_subscription *sub = zalloc(sizeof(*sub));
150
151 if (!sub)
152 return;
153
154 sub->scope_name = strdup(scope_name);
155 sub->owner = owner;
156
157 wl_list_insert(&log_ctx->pending_subscription_list, &sub->source_link);
158}
159
160/** Destroys the pending subscription created previously with
161 * weston_log_subscription_create_pending()
162 *
163 * @param sub the weston_log_subscription object to remove from the list
164 * of subscriptions and to destroy the subscription
165 *
166 * @memberof weston_log_subscription
167 */
168static void
169weston_log_subscription_destroy_pending(struct weston_log_subscription *sub)
170{
171 assert(sub);
172 /* pending subsriptions do not have a source */
173 wl_list_remove(&sub->source_link);
174 free(sub->scope_name);
175 free(sub);
176}
177
Marius Vlad8b8b8032019-06-27 18:34:03 +0300178/** Write to the stream's subscription
179 *
180 * @memberof weston_log_subscription
181 */
Marius Vladdad882a2019-07-17 15:43:53 +0300182static void
183weston_log_subscription_write(struct weston_log_subscription *sub,
184 const char *data, size_t len)
185{
186 if (sub->owner && sub->owner->write)
187 sub->owner->write(sub->owner, data, len);
188}
189
Marius Vlad8b8b8032019-06-27 18:34:03 +0300190/** Write a formatted string to the stream's subscription
191 *
192 * @memberof weston_log_subscription
193 */
Marius Vladdad882a2019-07-17 15:43:53 +0300194static void
195weston_log_subscription_vprintf(struct weston_log_subscription *sub,
196 const char *fmt, va_list ap)
197{
198 static const char oom[] = "Out of memory";
199 char *str;
200 int len;
201
202 if (!weston_log_scope_is_enabled(sub->source))
203 return;
204
205 len = vasprintf(&str, fmt, ap);
206 if (len >= 0) {
207 weston_log_subscription_write(sub, str, len);
208 free(str);
209 } else {
210 weston_log_subscription_write(sub, oom, sizeof oom - 1);
211 }
212}
213
Marius Vlad410d0bc2019-07-29 12:05:29 +0300214void
215weston_log_subscription_set_data(struct weston_log_subscription *sub, void *data)
216{
217 /* don't allow data to already be set */
218 assert(!sub->data);
219 sub->data = data;
220}
221
222void *
223weston_log_subscription_get_data(struct weston_log_subscription *sub)
224{
225 return sub->data;
226}
227
Marius Vlade0a858a2019-06-25 12:48:56 +0300228/** Creates a new subscription using the subscriber by \c owner.
229 *
230 * The subscription created is added to the \c owner subscription list.
231 * Destroying the subscription using weston_log_subscription_destroy() will
232 * remove the link from the subscription list and free storage alloc'ed.
233 *
Marius Vlad5ae0e622019-07-11 17:44:50 +0300234 * Note that this adds the subscription to the scope's subscription list
235 * hence the \c scope required argument.
236 *
Marius Vlade0a858a2019-06-25 12:48:56 +0300237 * @param owner the subscriber owner, must be created before creating a
238 * subscription
Marius Vlad5ae0e622019-07-11 17:44:50 +0300239 * @param scope the scope in order to add the subscription to the scope's
240 * subscription list
Marius Vlade0a858a2019-06-25 12:48:56 +0300241 * @returns a weston_log_subscription object in case of success, or NULL
242 * otherwise
243 *
Marius Vlade0a858a2019-06-25 12:48:56 +0300244 * @sa weston_log_subscription_destroy, weston_log_subscription_remove,
245 * weston_log_subscription_add
Marius Vlad8b8b8032019-06-27 18:34:03 +0300246 * @memberof weston_log_subscription
Marius Vlade0a858a2019-06-25 12:48:56 +0300247 */
Marius Vlad5ae0e622019-07-11 17:44:50 +0300248void
Marius Vlade0a858a2019-06-25 12:48:56 +0300249weston_log_subscription_create(struct weston_log_subscriber *owner,
Marius Vlad5ae0e622019-07-11 17:44:50 +0300250 struct weston_log_scope *scope)
Marius Vlade0a858a2019-06-25 12:48:56 +0300251{
252 struct weston_log_subscription *sub;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300253 assert(owner);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300254 assert(scope);
255 assert(scope->name);
Marius Vlade0a858a2019-06-25 12:48:56 +0300256
257 sub = zalloc(sizeof(*sub));
258 if (!sub)
Marius Vlad5ae0e622019-07-11 17:44:50 +0300259 return;
Marius Vlade0a858a2019-06-25 12:48:56 +0300260
261 sub->owner = owner;
Marius Vlad5ae0e622019-07-11 17:44:50 +0300262 sub->scope_name = strdup(scope->name);
Marius Vlade0a858a2019-06-25 12:48:56 +0300263
264 wl_list_insert(&sub->owner->subscription_list, &sub->owner_link);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300265
266 weston_log_subscription_add(scope, sub);
Marius Vlad0c7beb02019-07-25 11:46:44 +0300267 weston_log_run_cb_new_subscription(sub);
Marius Vlade0a858a2019-06-25 12:48:56 +0300268}
269
270/** Destroys the subscription
271 *
Marius Vlad5ae0e622019-07-11 17:44:50 +0300272 * Removes the subscription from the scopes subscription list and from
273 * subscriber's subscription list. It destroys the subscription afterwads.
274 *
275 * @memberof weston_log_subscription
Marius Vlade0a858a2019-06-25 12:48:56 +0300276 */
277void
278weston_log_subscription_destroy(struct weston_log_subscription *sub)
279{
Marius Vlad5ae0e622019-07-11 17:44:50 +0300280 assert(sub);
Marius Vlad9bb1c3a2019-07-29 12:02:47 +0300281
Leandro Ribeiro97d2d692020-02-07 16:06:19 -0300282 if (sub->owner->destroy_subscription)
283 sub->owner->destroy_subscription(sub->owner);
284
Marius Vlad9bb1c3a2019-07-29 12:02:47 +0300285 if (sub->source->destroy_subscription)
286 sub->source->destroy_subscription(sub, sub->source->user_data);
287
Marius Vlade0a858a2019-06-25 12:48:56 +0300288 if (sub->owner)
289 wl_list_remove(&sub->owner_link);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300290
291 weston_log_subscription_remove(sub);
Marius Vlade0a858a2019-06-25 12:48:56 +0300292 free(sub->scope_name);
293 free(sub);
294}
295
Marius Vlade0a858a2019-06-25 12:48:56 +0300296/** Adds the subscription \c sub to the subscription list of the
297 * scope.
298 *
299 * This should used when the scope has been created, and the subscription \c
300 * sub has be created before calling this function.
301 *
302 * @param scope the scope
303 * @param sub the subscription, it must be created before, see
304 * weston_log_subscription_create()
305 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300306 * @memberof weston_log_subscription
Marius Vlade0a858a2019-06-25 12:48:56 +0300307 */
308void
309weston_log_subscription_add(struct weston_log_scope *scope,
310 struct weston_log_subscription *sub)
311{
312 assert(scope);
313 assert(sub);
314 /* don't allow subscriptions to have a source already! */
315 assert(!sub->source);
316
317 sub->source = scope;
318 wl_list_insert(&scope->subscription_list, &sub->source_link);
319}
320
321/** Removes the subscription from the scope's subscription list
322 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300323 * @memberof weston_log_subscription
Marius Vlade0a858a2019-06-25 12:48:56 +0300324 */
325void
326weston_log_subscription_remove(struct weston_log_subscription *sub)
327{
328 assert(sub);
329 if (sub->source)
330 wl_list_remove(&sub->source_link);
331 sub->source = NULL;
332}
333
Marius Vlad8f329e22019-06-21 14:57:02 +0300334/** Look-up the scope from the scope list stored in the log context, by
335 * matching against the \c name.
336 *
337 * @param log_ctx
Leandro Ribeirof66685d2019-12-26 16:03:04 -0300338 * @param name the scope name, see weston_log_ctx_add_log_scope() and
339 * weston_compositor_add_log_scope()
Marius Vlad8f329e22019-06-21 14:57:02 +0300340 * @returns NULL if none found, or a pointer to a weston_log_scope
341 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300342 * @ingroup internal-log
Marius Vlad8f329e22019-06-21 14:57:02 +0300343 */
344struct weston_log_scope *
345weston_log_get_scope(struct weston_log_context *log_ctx, const char *name)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200346{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300347 struct weston_log_scope *scope;
Marius Vlad3d7d9782019-04-17 12:35:38 +0300348 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200349 if (strcmp(name, scope->name) == 0)
350 return scope;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200351 return NULL;
352}
353
Marius Vlad0c7beb02019-07-25 11:46:44 +0300354/** Wrapper to invoke the weston_log_scope_cb. Allows to call the cb
355 * new_subscription of a log scope.
Marius Vlad8f329e22019-06-21 14:57:02 +0300356 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300357 * @ingroup internal-log
Marius Vlad8f329e22019-06-21 14:57:02 +0300358 */
359void
Marius Vlad0c7beb02019-07-25 11:46:44 +0300360weston_log_run_cb_new_subscription(struct weston_log_subscription *sub)
Marius Vlad8f329e22019-06-21 14:57:02 +0300361{
Marius Vlad0c7beb02019-07-25 11:46:44 +0300362 if (sub->source->new_subscription)
363 sub->source->new_subscription(sub, sub->source->user_data);
Marius Vlad8f329e22019-06-21 14:57:02 +0300364}
365
366/** Advertise the log scope name and the log scope description
367 *
368 * This is only used by the weston-debug protocol!
369 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300370 * @ingroup internal-log
Marius Vlad8f329e22019-06-21 14:57:02 +0300371 */
372void
373weston_debug_protocol_advertise_scopes(struct weston_log_context *log_ctx,
374 struct wl_resource *res)
375{
376 struct weston_log_scope *scope;
377 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
378 weston_debug_v1_send_available(res, scope->name, scope->desc);
379}
380
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300381/** Disable debug-protocol
382 *
383 * @param log_ctx The log context where the debug-protocol is linked
384 *
385 * @ingroup internal-log
386 */
387static void
388weston_log_ctx_disable_debug_protocol(struct weston_log_context *log_ctx)
389{
390 if (!log_ctx->global)
391 return;
392
393 wl_global_destroy(log_ctx->global);
394 log_ctx->global = NULL;
395}
396
Marius Vlada2dace22019-06-12 16:05:44 +0300397/** Creates weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200398 *
Marius Vlada2dace22019-06-12 16:05:44 +0300399 * \return NULL in case of failure, or a weston_log_context object in case of
400 * success
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200401 *
Marius Vlad3d7d9782019-04-17 12:35:38 +0300402 * weston_log_context is a singleton for each weston_compositor.
Marius Vlad8b8b8032019-06-27 18:34:03 +0300403 * @ingroup log
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200404 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200405 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300406WL_EXPORT struct weston_log_context *
Leandro Ribeiro4f135952020-01-17 11:19:59 -0300407weston_log_ctx_create(void)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200408{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300409 struct weston_log_context *log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200410
Marius Vlad3d7d9782019-04-17 12:35:38 +0300411 log_ctx = zalloc(sizeof *log_ctx);
412 if (!log_ctx)
Marius Vlad880b4852019-04-07 17:07:58 +0300413 return NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200414
Marius Vlad3d7d9782019-04-17 12:35:38 +0300415 wl_list_init(&log_ctx->scope_list);
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300416 wl_list_init(&log_ctx->pending_subscription_list);
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300417 wl_list_init(&log_ctx->compositor_destroy_listener.link);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200418
Marius Vlad3d7d9782019-04-17 12:35:38 +0300419 return log_ctx;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200420}
421
Marius Vlad3d7d9782019-04-17 12:35:38 +0300422/** Destroy weston_log_context structure
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200423 *
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300424 * \param log_ctx The log context to destroy.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200425 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300426 * @ingroup log
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200427 *
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200428 */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300429WL_EXPORT void
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300430weston_log_ctx_destroy(struct weston_log_context *log_ctx)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200431{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300432 struct weston_log_scope *scope;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300433 struct weston_log_subscription *pending_sub, *pending_sub_tmp;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200434
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300435 /* We can't destroy the log context if there's still a compositor
436 * that depends on it. This is an user error */
437 assert(wl_list_empty(&log_ctx->compositor_destroy_listener.link));
438
439 weston_log_ctx_disable_debug_protocol(log_ctx);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200440
Marius Vlad3d7d9782019-04-17 12:35:38 +0300441 wl_list_for_each(scope, &log_ctx->scope_list, compositor_link)
Marius Vladef4c2682019-06-23 15:48:54 +0300442 fprintf(stderr, "Internal warning: debug scope '%s' has not been destroyed.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200443 scope->name);
444
445 /* Remove head to not crash if scope removed later. */
Marius Vlad3d7d9782019-04-17 12:35:38 +0300446 wl_list_remove(&log_ctx->scope_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200447
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300448 /* Remove any pending subscription(s) which nobody subscribed to */
449 wl_list_for_each_safe(pending_sub, pending_sub_tmp,
450 &log_ctx->pending_subscription_list, source_link) {
451 weston_log_subscription_destroy_pending(pending_sub);
452 }
453
454 /* pending_subscription_list should be empty at this point */
455
Marius Vlad3d7d9782019-04-17 12:35:38 +0300456 free(log_ctx);
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300457}
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200458
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300459static void
460compositor_destroy_listener(struct wl_listener *listener, void *data)
461{
462 struct weston_log_context *log_ctx =
463 wl_container_of(listener, log_ctx, compositor_destroy_listener);
464
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -0500465 /* We have to keep this list initialized as weston_log_ctx_destroy() has
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300466 * to check if there's any compositor destroy listener registered */
467 wl_list_remove(&log_ctx->compositor_destroy_listener.link);
468 wl_list_init(&log_ctx->compositor_destroy_listener.link);
469
470 weston_log_ctx_disable_debug_protocol(log_ctx);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200471}
472
473/** Enable weston-debug protocol extension
474 *
475 * \param compositor The libweston compositor where to enable.
476 *
477 * This enables the weston_debug_v1 Wayland protocol extension which any client
Emmanuel Gil Peyrot426c2462019-02-20 16:33:32 +0100478 * can use to get debug messages from the compositor.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200479 *
480 * WARNING: This feature should not be used in production. If a client
481 * provides a file descriptor that blocks writes, it will block the whole
482 * compositor indefinitely.
483 *
484 * There is no control on which client is allowed to subscribe to debug
485 * messages. Any and all clients are allowed.
486 *
487 * The debug extension is disabled by default, and once enabled, cannot be
488 * disabled again.
Marius Vlad8b8b8032019-06-27 18:34:03 +0300489 *
490 * @ingroup debug-protocol
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200491 */
492WL_EXPORT void
493weston_compositor_enable_debug_protocol(struct weston_compositor *compositor)
494{
Marius Vlad1e2fda22019-04-07 19:07:16 +0300495 struct weston_log_context *log_ctx = compositor->weston_log_ctx;
496 assert(log_ctx);
497 if (log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200498 return;
499
Marius Vlad1e2fda22019-04-07 19:07:16 +0300500 log_ctx->global = wl_global_create(compositor->wl_display,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200501 &weston_debug_v1_interface, 1,
Marius Vlad69e75712019-06-25 13:29:57 +0300502 log_ctx, weston_log_bind_weston_debug);
Marius Vlad1e2fda22019-04-07 19:07:16 +0300503 if (!log_ctx->global)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200504 return;
505
Leandro Ribeiro4ec38d12020-01-24 01:12:59 -0300506 log_ctx->compositor_destroy_listener.notify = compositor_destroy_listener;
507 wl_signal_add(&compositor->destroy_signal, &log_ctx->compositor_destroy_listener);
508
Marius Vladef4c2682019-06-23 15:48:54 +0300509 fprintf(stderr, "WARNING: debug protocol has been enabled. "
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200510 "This is a potential denial-of-service attack vector and "
511 "information leak.\n");
512}
513
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200514/** Determine if the debug protocol has been enabled
515 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300516 * \param wc The libweston compositor to verify if debug protocol has been
517 * enabled
518 *
519 * @ingroup debug-protocol
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200520 */
521WL_EXPORT bool
522weston_compositor_is_debug_protocol_enabled(struct weston_compositor *wc)
523{
Marius Vlad3d7d9782019-04-17 12:35:38 +0300524 return wc->weston_log_ctx->global != NULL;
Marius Vladd9bcc0b2018-12-13 23:03:30 +0200525}
526
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300527/** Register a new stream name, creating a log scope.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200528 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300529 * @param log_ctx The weston_log_context where to add.
530 * @param name The debug stream/scope name; must not be NULL.
531 * @param description The log scope description for humans; must not be NULL.
Marius Vlad0c7beb02019-07-25 11:46:44 +0300532 * @param new_subscription Optional callback when a client subscribes to this
Marius Vladdad882a2019-07-17 15:43:53 +0300533 * scope.
Marius Vlad9bb1c3a2019-07-29 12:02:47 +0300534 * @param destroy_subscription Optional callback when a client destroys the
535 * subscription.
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300536 * @param user_data Optional user data pointer for the callback.
537 * @returns A valid pointer on success, NULL on failure.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200538 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300539 * This function is used to create a log scope. All debug message printing
540 * happens for a scope, which allows clients to subscribe to the kind of debug
541 * messages they want by \c name. For the weston-debug protocol,
542 * subscription for the scope will happen automatically but for other types of
543 * streams, weston_log_subscribe() should be called as to create a subscription
544 * and tie it to the scope created by this function.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200545 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300546 * \p name must be unique in the weston_compositor instance. \p name
547 * and \p description must both be provided. In case of the weston-debug
548 * protocol, the description is printed when a client asks for a list of
549 * supported log scopes.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200550 *
Marius Vlad0c7beb02019-07-25 11:46:44 +0300551 * \p new_subscription, if not NULL, is called when a client subscribes to the log
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300552 * scope creating a debug stream. This is for log scopes that need to print
553 * messages as a response to a client appearing, e.g. printing a list of
554 * windows on demand or a static preamble. The argument \p user_data is
555 * passed in to the callback and is otherwise unused.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200556 *
Marius Vlad0c7beb02019-07-25 11:46:44 +0300557 * For one-shot debug streams, \c new_subscription should finally call
Marius Vladdad882a2019-07-17 15:43:53 +0300558 * weston_log_subscription_complete() to close the stream and tell the client
559 * the printing is complete. Otherwise the client expects more data to be
560 * written. The complete callback in weston_log_subscriber should be installed
561 * to trigger it and it is set-up automatically for the weston-debug protocol.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200562 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300563 * As subscription can take place before creating the scope, any pending
564 * subscriptions to scope added by weston_log_subscribe(), will be checked
565 * against the scope being created and if found will be added to the scope's
566 * subscription list.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200567 *
Leandro Ribeirof0149642019-12-18 15:52:18 -0300568 * The log scope must be destroyed using weston_log_scope_destroy()
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300569 * before destroying the weston_compositor.
570 *
571 * @memberof weston_log_scope
572 * @sa weston_log_scope_cb, weston_log_subscribe
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200573 */
Marius Vlad5d5e3352019-04-17 13:05:38 +0300574WL_EXPORT struct weston_log_scope *
Leandro Ribeiro5976dbb2019-12-18 15:21:03 -0300575weston_log_ctx_add_log_scope(struct weston_log_context *log_ctx,
576 const char *name,
577 const char *description,
578 weston_log_scope_cb new_subscription,
579 weston_log_scope_cb destroy_subscription,
580 void *user_data)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200581{
Marius Vlad5d5e3352019-04-17 13:05:38 +0300582 struct weston_log_scope *scope;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300583 struct weston_log_subscription *pending_sub = NULL;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200584
Marius Vlad1e2fda22019-04-07 19:07:16 +0300585 if (!name || !description) {
Marius Vladef4c2682019-06-23 15:48:54 +0300586 fprintf(stderr, "Error: cannot add a debug scope without name or description.\n");
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200587 return NULL;
588 }
589
Marius Vlad3d7d9782019-04-17 12:35:38 +0300590 if (!log_ctx) {
Marius Vladef4c2682019-06-23 15:48:54 +0300591 fprintf(stderr, "Error: cannot add debug scope '%s', infra not initialized.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200592 name);
593 return NULL;
594 }
595
Dongjin Kimba89f002024-09-30 17:49:36 +0900596 if (weston_log_get_scope(log_ctx, name)) {
Marius Vladef4c2682019-06-23 15:48:54 +0300597 fprintf(stderr, "Error: debug scope named '%s' is already registered.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200598 name);
599 return NULL;
600 }
601
602 scope = zalloc(sizeof *scope);
603 if (!scope) {
Marius Vladef4c2682019-06-23 15:48:54 +0300604 fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200605 name);
606 return NULL;
607 }
608
609 scope->name = strdup(name);
610 scope->desc = strdup(description);
Marius Vlad0c7beb02019-07-25 11:46:44 +0300611 scope->new_subscription = new_subscription;
Marius Vlad9bb1c3a2019-07-29 12:02:47 +0300612 scope->destroy_subscription = destroy_subscription;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200613 scope->user_data = user_data;
Marius Vlad7814f302019-06-21 14:20:15 +0300614 wl_list_init(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200615
616 if (!scope->name || !scope->desc) {
Marius Vladef4c2682019-06-23 15:48:54 +0300617 fprintf(stderr, "Error adding debug scope '%s': out of memory.\n",
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200618 name);
619 free(scope->name);
620 free(scope->desc);
621 free(scope);
622 return NULL;
623 }
624
Marius Vlad3d7d9782019-04-17 12:35:38 +0300625 wl_list_insert(log_ctx->scope_list.prev, &scope->compositor_link);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200626
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300627 /* check if there are any pending subscriptions to this scope */
628 while ((pending_sub = find_pending_subscription(log_ctx, scope->name)) != NULL) {
Marius Vlad5ae0e622019-07-11 17:44:50 +0300629 weston_log_subscription_create(pending_sub->owner, scope);
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300630
631 /* remove it from pending */
632 weston_log_subscription_destroy_pending(pending_sub);
633 }
634
635
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200636 return scope;
637}
638
Leandro Ribeirof66685d2019-12-26 16:03:04 -0300639/** Register a new stream name, creating a log scope.
640 *
641 * @param compositor The compositor that contains the log context where the log
642 * scope will be linked.
643 * @param name The debug stream/scope name; must not be NULL.
644 * @param description The log scope description for humans; must not be NULL.
645 * @param new_subscription Optional callback when a client subscribes to this
646 * scope.
647 * @param destroy_subscription Optional callback when a client destroys the
648 * subscription.
649 * @param user_data Optional user data pointer for the callback.
650 * @returns A valid pointer on success, NULL on failure.
651 *
652 * This function works like weston_log_ctx_add_log_scope(), but the log scope
653 * created is linked to the log context of \c compositor.
654 *
655 * @memberof weston_compositor
656 * @sa weston_log_ctx_add_log_scope
657 */
658WL_EXPORT struct weston_log_scope *
659weston_compositor_add_log_scope(struct weston_compositor *compositor,
660 const char *name,
661 const char *description,
662 weston_log_scope_cb new_subscription,
663 weston_log_scope_cb destroy_subscription,
664 void *user_data)
665{
666 struct weston_log_scope *scope;
667 scope = weston_log_ctx_add_log_scope(compositor->weston_log_ctx,
668 name, description,
Dongjin Kimba89f002024-09-30 17:49:36 +0900669 new_subscription,
Leandro Ribeirof66685d2019-12-26 16:03:04 -0300670 destroy_subscription,
671 user_data);
672 return scope;
673}
674
Marius Vlad3d7d9782019-04-17 12:35:38 +0300675/** Destroy a log scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200676 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300677 * @param scope The log scope to destroy; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200678 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300679 * Destroys the log scope, calling each stream's destroy callback if one was
680 * installed/created.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200681 *
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300682 * @memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200683 */
684WL_EXPORT void
Leandro Ribeirof0149642019-12-18 15:52:18 -0300685weston_log_scope_destroy(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200686{
Marius Vlad7814f302019-06-21 14:20:15 +0300687 struct weston_log_subscription *sub, *sub_tmp;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200688
689 if (!scope)
690 return;
691
Leandro Ribeiro97d2d692020-02-07 16:06:19 -0300692 wl_list_for_each_safe(sub, sub_tmp, &scope->subscription_list, source_link)
Marius Vlad7814f302019-06-21 14:20:15 +0300693 weston_log_subscription_destroy(sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200694
695 wl_list_remove(&scope->compositor_link);
696 free(scope->name);
697 free(scope->desc);
698 free(scope);
699}
700
701/** Are there any active subscriptions to the scope?
702 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300703 * \param scope The log scope to check; may be NULL.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200704 * \return True if any streams are open for this scope, false otherwise.
705 *
706 * As printing some debugging messages may be relatively expensive, one
707 * can use this function to determine if there is a need to gather the
708 * debugging information at all. If this function returns false, all
709 * printing for this scope is dropped, so gathering the information is
710 * pointless.
711 *
712 * The return value of this function should not be stored, as new clients
713 * may subscribe to the debug scope later.
714 *
715 * If the given scope is NULL, this function will always return false,
716 * making it safe to use in teardown or destroy code, provided the
717 * scope is initialized to NULL before creation and set to NULL after
718 * destruction.
719 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300720 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200721 */
722WL_EXPORT bool
Marius Vlad7e4db952019-04-17 13:47:06 +0300723weston_log_scope_is_enabled(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200724{
725 if (!scope)
726 return false;
727
Marius Vlad7814f302019-06-21 14:20:15 +0300728 return !wl_list_empty(&scope->subscription_list);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200729}
730
Marius Vladdad882a2019-07-17 15:43:53 +0300731/** Close the stream's complete callback if one was installed/created.
732 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300733 * @ingroup log
Marius Vladdad882a2019-07-17 15:43:53 +0300734 */
735WL_EXPORT void
736weston_log_subscription_complete(struct weston_log_subscription *sub)
737{
738 if (sub->owner && sub->owner->complete)
739 sub->owner->complete(sub->owner);
740}
741
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300742/** Close the log scope.
743 *
744 * @param scope The log scope to complete; may be NULL.
745 *
746 * Complete the log scope, calling each stream's complete callback if one was
747 * installed/created. This can be useful to signal the reading end that the
Maxime Roussin-Bélanger1d009c22020-12-17 17:10:13 -0500748 * data has been transmitted and should no longer expect that written over the
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300749 * stream. Particularly useful for the weston-debug protocol.
750 *
751 * @memberof weston_log_scope
Leandro Ribeiroac691a82019-12-18 15:21:03 -0300752 * @sa weston_log_ctx_add_log_scope, weston_compositor_add_log_scope,
753 * weston_log_scope_destroy
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300754 */
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200755WL_EXPORT void
Marius Vlad7814f302019-06-21 14:20:15 +0300756weston_log_scope_complete(struct weston_log_scope *scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200757{
Marius Vlad7814f302019-06-21 14:20:15 +0300758 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200759
Marius Vlad7814f302019-06-21 14:20:15 +0300760 if (!scope)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200761 return;
762
Marius Vlad7814f302019-06-21 14:20:15 +0300763 wl_list_for_each(sub, &scope->subscription_list, source_link)
Marius Vladdad882a2019-07-17 15:43:53 +0300764 weston_log_subscription_complete(sub);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200765}
766
Marius Vlad7e4db952019-04-17 13:47:06 +0300767/** Write log data for a scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200768 *
769 * \param scope The debug scope to write for; may be NULL, in which case
770 * nothing will be written.
Marius Vlada2dace22019-06-12 16:05:44 +0300771 * \param[in] data Pointer to the data to write.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200772 * \param len Number of bytes to write.
773 *
774 * Writes the given data to all subscribed clients' streams.
775 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300776 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200777 */
778WL_EXPORT void
Marius Vlad7e4db952019-04-17 13:47:06 +0300779weston_log_scope_write(struct weston_log_scope *scope,
780 const char *data, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200781{
Marius Vlad7814f302019-06-21 14:20:15 +0300782 struct weston_log_subscription *sub;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200783
784 if (!scope)
785 return;
786
Marius Vlad7814f302019-06-21 14:20:15 +0300787 wl_list_for_each(sub, &scope->subscription_list, source_link)
Marius Vladdad882a2019-07-17 15:43:53 +0300788 weston_log_subscription_write(sub, data, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200789}
790
791/** Write a formatted string for a scope (varargs)
792 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300793 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200794 * nothing will be written.
795 * \param fmt Printf-style format string.
796 * \param ap Formatting arguments.
797 *
798 * Writes to formatted string to all subscribed clients' streams.
799 *
800 * The behavioral details for each stream are the same as for
801 * weston_debug_stream_write().
802 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300803 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200804 */
Marius Vlad843b2382019-08-06 17:37:51 +0300805WL_EXPORT int
Marius Vlad7e4db952019-04-17 13:47:06 +0300806weston_log_scope_vprintf(struct weston_log_scope *scope,
807 const char *fmt, va_list ap)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200808{
809 static const char oom[] = "Out of memory";
810 char *str;
Marius Vlad843b2382019-08-06 17:37:51 +0300811 int len = 0;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200812
Marius Vlad7e4db952019-04-17 13:47:06 +0300813 if (!weston_log_scope_is_enabled(scope))
Marius Vlad843b2382019-08-06 17:37:51 +0300814 return len;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200815
816 len = vasprintf(&str, fmt, ap);
817 if (len >= 0) {
Marius Vlad7e4db952019-04-17 13:47:06 +0300818 weston_log_scope_write(scope, str, len);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200819 free(str);
820 } else {
Marius Vlad7e4db952019-04-17 13:47:06 +0300821 weston_log_scope_write(scope, oom, sizeof oom - 1);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200822 }
Marius Vlad843b2382019-08-06 17:37:51 +0300823
824 return len;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200825}
826
827/** Write a formatted string for a scope
828 *
Marius Vlad7e4db952019-04-17 13:47:06 +0300829 * \param scope The log scope to write for; may be NULL, in which case
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200830 * nothing will be written.
831 * \param fmt Printf-style format string and arguments.
832 *
833 * Writes to formatted string to all subscribed clients' streams.
834 *
835 * The behavioral details for each stream are the same as for
836 * weston_debug_stream_write().
837 *
Marius Vlad5d5e3352019-04-17 13:05:38 +0300838 * \memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200839 */
Marius Vlad843b2382019-08-06 17:37:51 +0300840WL_EXPORT int
Marius Vlad7e4db952019-04-17 13:47:06 +0300841weston_log_scope_printf(struct weston_log_scope *scope,
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200842 const char *fmt, ...)
843{
844 va_list ap;
Marius Vlad843b2382019-08-06 17:37:51 +0300845 int len;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200846
847 va_start(ap, fmt);
Marius Vlad843b2382019-08-06 17:37:51 +0300848 len = weston_log_scope_vprintf(scope, fmt, ap);
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200849 va_end(ap);
Marius Vlad843b2382019-08-06 17:37:51 +0300850
851 return len;
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200852}
853
Marius Vladdad882a2019-07-17 15:43:53 +0300854/** Write a formatted string for a subscription
855 *
856 * \param sub The subscription to write for; may be NULL, in which case
857 * nothing will be written.
858 * \param fmt Printf-style format string and arguments.
859 *
860 * Writes to formatted string to the stream that created the subscription.
861 *
Marius Vlad8b8b8032019-06-27 18:34:03 +0300862 * @ingroup log
Marius Vladdad882a2019-07-17 15:43:53 +0300863 */
864WL_EXPORT void
865weston_log_subscription_printf(struct weston_log_subscription *sub,
866 const char *fmt, ...)
867{
868 va_list ap;
869
870 va_start(ap, fmt);
871 weston_log_subscription_vprintf(sub, fmt, ap);
872 va_end(ap);
873}
874
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200875/** Write debug scope name and current time into string
876 *
Marius Vlada2dace22019-06-12 16:05:44 +0300877 * \param[in] scope debug scope; may be NULL
878 * \param[out] buf Buffer to store the string.
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200879 * \param len Available size in the buffer in bytes.
880 * \return \c buf
881 *
882 * Reads the current local wall-clock time and formats it into a string.
883 * and append the debug scope name to it, if a scope is available.
884 * The string is NUL-terminated, even if truncated.
Marius Vlad8b8b8032019-06-27 18:34:03 +0300885 *
886 * @memberof weston_log_scope
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200887 */
888WL_EXPORT char *
Marius Vlad7e4db952019-04-17 13:47:06 +0300889weston_log_scope_timestamp(struct weston_log_scope *scope,
890 char *buf, size_t len)
Pekka Paalanena5630ea2017-10-12 13:13:42 +0200891{
892 struct timeval tv;
893 struct tm *bdt;
894 char string[128];
895 size_t ret = 0;
896
897 gettimeofday(&tv, NULL);
898
899 bdt = localtime(&tv.tv_sec);
900 if (bdt)
901 ret = strftime(string, sizeof string,
902 "%Y-%m-%d %H:%M:%S", bdt);
903
904 if (ret > 0) {
905 snprintf(buf, len, "[%s.%03ld][%s]", string,
906 tv.tv_usec / 1000,
907 (scope) ? scope->name : "no scope");
908 } else {
909 snprintf(buf, len, "[?][%s]",
910 (scope) ? scope->name : "no scope");
911 }
912
913 return buf;
914}
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300915
Leandro Ribeiro23491cd2020-02-03 22:59:16 -0300916void
917weston_log_subscriber_release(struct weston_log_subscriber *subscriber)
918{
919 struct weston_log_subscription *sub, *sub_tmp;
920
Leandro Ribeiro97d2d692020-02-07 16:06:19 -0300921 wl_list_for_each_safe(sub, sub_tmp, &subscriber->subscription_list, owner_link)
Leandro Ribeiro23491cd2020-02-03 22:59:16 -0300922 weston_log_subscription_destroy(sub);
Leandro Ribeiro23491cd2020-02-03 22:59:16 -0300923}
924
Leandro Ribeiro1ded6612020-02-06 16:43:51 -0300925/** Destroy a file type or a flight-rec type subscriber.
926 *
927 * They are created, respectively, with weston_log_subscriber_create_log()
928 * and weston_log_subscriber_create_flight_rec()
929 *
930 * @param subscriber the weston_log_subscriber object to destroy
931 *
932 * @ingroup log
933 */
934WL_EXPORT void
935weston_log_subscriber_destroy(struct weston_log_subscriber *subscriber)
936{
937 subscriber->destroy(subscriber);
938}
939
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300940/** Subscribe to a scope
941 *
942 * Creates a subscription which is used to subscribe the \p subscriber
943 * to the scope \c scope_name.
944 *
945 * If \c scope_name has already been created (using
Leandro Ribeirof66685d2019-12-26 16:03:04 -0300946 * weston_log_ctx_add_log_scope or weston_compositor_add_log_scope) the
947 * subscription will take place immediately, otherwise we store the
948 * subscription into a pending list. See also weston_log_ctx_add_log_scope()
949 * and weston_compositor_add_log_scope()
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300950 *
951 * @param log_ctx the log context, used for accessing pending list
952 * @param subscriber the subscriber, which has to be created before
953 * @param scope_name the scope name. In case the scope is not created
954 * we temporarily store the subscription in the pending list.
Marius Vlad8b8b8032019-06-27 18:34:03 +0300955 *
956 * @ingroup log
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300957 */
958WL_EXPORT void
959weston_log_subscribe(struct weston_log_context *log_ctx,
960 struct weston_log_subscriber *subscriber,
961 const char *scope_name)
962{
963 assert(log_ctx);
964 assert(subscriber);
965 assert(scope_name);
966
967 struct weston_log_scope *scope;
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300968
969 scope = weston_log_get_scope(log_ctx, scope_name);
Marius Vlad5ae0e622019-07-11 17:44:50 +0300970 if (scope)
971 weston_log_subscription_create(subscriber, scope);
972 else
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300973 /*
974 * if we don't have already as scope for it, add it to pending
975 * subscription list
976 */
977 weston_log_subscription_create_pending(subscriber, scope_name, log_ctx);
Marius Vlad9f71a4a2019-06-22 00:29:31 +0300978}
Marius Vladd0d89d02019-08-06 19:22:53 +0300979
980/** Iterate over all subscriptions in a scope
981 *
982 * @param scope the scope for which you want to iterate
983 * @param sub_iter the iterator, use NULL to start from the 'head'
984 * @returns the next subscription from the log scope
985 *
986 * This is (quite) useful when 'log_scope' and 'log_subscription' are opaque. Do note
987 * that \c sub_iter needs to be NULL-initialized before calling this function.
988 *
989 */
990WL_EXPORT struct weston_log_subscription *
991weston_log_subscription_iterate(struct weston_log_scope *scope,
992 struct weston_log_subscription *sub_iter)
993{
994 struct wl_list *list = &scope->subscription_list;
995 struct wl_list *node;
996
997 /* go to the next item in the list or if not set starts with the head */
998 if (sub_iter)
999 node = sub_iter->source_link.next;
1000 else
1001 node = list->next;
1002
1003 assert(node);
1004 assert(!sub_iter || node != &sub_iter->source_link);
1005
1006 /* if we're at the end */
1007 if (node == list)
1008 return NULL;
1009
1010 return container_of(node, struct weston_log_subscription, source_link);
1011}