1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2From: Lloyd Pique <[email protected]> 3Date: Fri, 11 Mar 2022 17:57:37 -0800 4Subject: [PATCH 3/6] protocol-logger-test: Demonstrate logging 5 6Client message observers 3/6 7 8Adds code demonstrating how to replicate the output produced by the internal 9wl_closure_print() using the client message observer interface. 10 11If you run protocol-logger-test with "WAYLAND_DEBUG=client", you can see the 12client messages logged to stderr twice, with the same strings. 13 14Signed-off-by: Lloyd Pique <[email protected]> 15 16diff --git a/tests/protocol-logger-test.c b/tests/protocol-logger-test.c 17index 3b9dc3e..082f055 100644 18--- a/tests/protocol-logger-test.c 19+++ b/tests/protocol-logger-test.c 20@@ -80,6 +80,7 @@ struct client { 21 struct wl_display *display; 22 struct wl_callback *cb; 23 struct wl_client_observer *sequence_observer; 24+ struct wl_client_observer *stderr_logger; 25 26 struct expected_client_message *expected_msg; 27 int expected_msg_count; 28@@ -190,6 +191,130 @@ client_sequence_observer_func( 29 "arg count mismatch: %s", details_msg); 30 } 31 32+// A slightly simplified version of get_next_argument() from src/connection.c 33+static const char * 34+get_next_argument_type(const char *signature, char *type) 35+{ 36+ for (; *signature; ++signature) { 37+ assert(strchr("iufsonah?", *signature) != NULL); 38+ switch (*signature) { 39+ case 'i': 40+ case 'u': 41+ case 'f': 42+ case 's': 43+ case 'o': 44+ case 'n': 45+ case 'a': 46+ case 'h': 47+ *type = *signature; 48+ return signature + 1; 49+ case '?': 50+ break; 51+ } 52+ } 53+ *type = 0; 54+ return signature; 55+} 56+ 57+// This duplicates what the internal wl_closure_print function does, and can be 58+// used as a starting point for a client or server that wants to log messages. 59+static void 60+client_log_to_stderr_demo(void *user_data, enum wl_client_message_type type, 61+ const struct wl_client_observed_message *message) 62+{ 63+ int i; 64+ char arg_type; 65+ const char *signature = message->message->signature; 66+ const union wl_argument *args = message->arguments; 67+ struct wl_proxy *arg_proxy; 68+ const char *arg_class; 69+ struct timespec tp; 70+ unsigned long long time; 71+ FILE *f; 72+ char *buffer; 73+ size_t buffer_length; 74+ 75+ f = open_memstream(&buffer, &buffer_length); 76+ if (f == NULL) 77+ return; 78+ 79+ clock_gettime(CLOCK_REALTIME, &tp); 80+ time = (tp.tv_sec * 1000000LL) + (tp.tv_nsec / 1000); 81+ 82+ // Note: server logger will be given message->resource, and should 83+ // use wl_resource_get_class and wl_resolurce_get_id. 84+ fprintf(f, "[%7llu.%03llu] %s%s%s%s%s@%u.%s(", time / 1000, time % 1000, 85+ (message->discarded_reason_str ? "discarded[" : ""), 86+ (message->discarded_reason_str ? message->discarded_reason_str 87+ : ""), 88+ (message->discarded_reason_str ? "] " : ""), 89+ (type == WL_CLIENT_MESSAGE_REQUEST) ? " -> " : "", 90+ wl_proxy_get_class(message->proxy), 91+ wl_proxy_get_id(message->proxy), message->message->name); 92+ 93+ for (i = 0; i < message->arguments_count; i++) { 94+ signature = get_next_argument_type(signature, &arg_type); 95+ if (i > 0) 96+ fprintf(f, ", "); 97+ 98+ switch (arg_type) { 99+ case 'u': 100+ fprintf(f, "%u", args[i].u); 101+ break; 102+ case 'i': 103+ fprintf(f, "%d", args[i].i); 104+ break; 105+ case 'f': 106+ fprintf(f, "%f", wl_fixed_to_double(args[i].f)); 107+ break; 108+ case 's': 109+ if (args[i].s) 110+ fprintf(f, "\"%s\"", args[i].s); 111+ else 112+ fprintf(f, "nil"); 113+ break; 114+ case 'o': 115+ if (args[i].o) { 116+ // Note: server logger should instead cast to 117+ // wl_resource, and use wl_resource_get_class 118+ // and wl_resource_get_id. 119+ arg_proxy = (struct wl_proxy *)(args[i].o); 120+ arg_class = wl_proxy_get_class(arg_proxy); 121+ 122+ fprintf(f, "%s@%u", 123+ arg_class ? arg_class : "[unknown]", 124+ wl_proxy_get_id(arg_proxy)); 125+ } else { 126+ fprintf(f, "nil"); 127+ } 128+ break; 129+ case 'n': 130+ fprintf(f, "new id %s@", 131+ (message->message->types[i]) 132+ ? message->message->types[i]->name 133+ : "[unknown]"); 134+ if (args[i].n != 0) 135+ fprintf(f, "%u", args[i].n); 136+ else 137+ fprintf(f, "nil"); 138+ break; 139+ case 'a': 140+ fprintf(f, "array"); 141+ break; 142+ case 'h': 143+ fprintf(f, "fd %d", args[i].h); 144+ break; 145+ } 146+ } 147+ 148+ fprintf(f, ")\n"); 149+ 150+ if (fclose(f) == 0) { 151+ fprintf(stderr, "%s", buffer); 152+ free(buffer); 153+ } 154+} 155+ 156 static void 157 callback_done(void *data, struct wl_callback *cb, uint32_t time) 158 { 159@@ -218,12 +343,15 @@ logger_setup(struct compositor *compositor, struct client *client) 160 client->display = wl_display_connect(socket); 161 client->sequence_observer = wl_display_create_client_observer( 162 client->display, client_sequence_observer_func, client); 163+ client->stderr_logger = wl_display_create_client_observer( 164+ client->display, client_log_to_stderr_demo, client); 165 } 166 167 static void 168 logger_teardown(struct compositor *compositor, struct client *client) 169 { 170 wl_client_observer_destroy(client->sequence_observer); 171+ wl_client_observer_destroy(client->stderr_logger); 172 wl_display_disconnect(client->display); 173 174 wl_client_destroy(compositor->client); 175