[pulseaudio-discuss] [PATCH] core: add ring buffer for log

Deng Zhengrong dzrongg at gmail.com
Sat Jun 23 04:17:49 PDT 2012


---
 src/daemon/daemon-conf.c        |    5 +-
 src/map-file                    |    1 +
 src/pulse/introspect.c          |   34 ++++++++++
 src/pulse/introspect.h          |    3 +
 src/pulsecore/cli-command.c     |    4 +-
 src/pulsecore/llist.h           |    3 +
 src/pulsecore/log.c             |  134 +++++++++++++++++++++++++++++++++++++++
 src/pulsecore/log.h             |    4 +
 src/pulsecore/native-common.h   |    1 +
 src/pulsecore/pdispatch.c       |    1 +
 src/pulsecore/protocol-native.c |   27 ++++++++
 src/pulsecore/strlist.c         |    1 -
 src/pulsecore/tagstruct.c       |    6 ++
 src/pulsecore/tagstruct.h       |    2 +
 src/pulsecore/thread-posix.c    |    4 +
 src/pulsecore/thread-win32.c    |    4 +
 src/pulsecore/thread.h          |    2 +
 src/utils/pactl.c               |   15 +++++
 18 files changed, 248 insertions(+), 3 deletions(-)

diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index dd2e7b6..80d7467 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -182,7 +182,10 @@ int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) {
 
     if (pa_streq(string, "auto"))
         c->auto_log_target = 1;
-    else if (pa_streq(string, "syslog")) {
+    else if (pa_streq(string, "ring")) {
+        c->auto_log_target = 0;
+        c->log_target = PA_LOG_RING;
+    } else if (pa_streq(string, "syslog")) {
         c->auto_log_target = 0;
         c->log_target = PA_LOG_SYSLOG;
     } else if (pa_streq(string, "stderr")) {
diff --git a/src/map-file b/src/map-file
index 69cf25b..812875a 100644
--- a/src/map-file
+++ b/src/map-file
@@ -46,6 +46,7 @@ pa_context_get_protocol_version;
 pa_context_get_sample_info_by_index;
 pa_context_get_sample_info_by_name;
 pa_context_get_sample_info_list;
+pa_context_get_log;
 pa_context_get_server;
 pa_context_get_server_info;
 pa_context_get_server_protocol_version;
diff --git a/src/pulse/introspect.c b/src/pulse/introspect.c
index 38a9d1c..2f2ef98 100644
--- a/src/pulse/introspect.c
+++ b/src/pulse/introspect.c
@@ -79,6 +79,40 @@ pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdat
     return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_cb_t) cb, userdata);
 }
 
+/*** Logs ***/
+static void context_get_log_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    pa_operation *o = userdata;
+    const char *p = NULL;
+
+    pa_assert(pd);
+    pa_assert(o);
+    pa_assert(PA_REFCNT_VALUE(o) >= 1);
+
+    if (!o->context)
+        goto finish;
+
+    if (command != PA_COMMAND_REPLY) {
+        if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
+            goto finish;
+    } else if (pa_tagstruct_gets(t, &p) < 0) {
+        pa_context_fail(o->context, PA_ERR_PROTOCOL);
+        goto finish;
+    }
+
+    if (o->callback) {
+        pa_log_info_cb_t cb = (pa_log_info_cb_t) o->callback;
+        cb(o->context, p, o->userdata);
+    }
+
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
+}
+
+pa_operation* pa_context_get_log(pa_context *c, pa_log_info_cb_t cb, void *userdata) {
+    return pa_context_send_simple_command(c, PA_COMMAND_GET_LOG, context_get_log_callback, (pa_operation_cb_t) cb, userdata);
+}
+
 /*** Server Info ***/
 
 static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
diff --git a/src/pulse/introspect.h b/src/pulse/introspect.h
index 0072f5d..62db314 100644
--- a/src/pulse/introspect.h
+++ b/src/pulse/introspect.h
@@ -629,6 +629,9 @@ pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdat
 
 /** @} */
 
+typedef void (*pa_log_info_cb_t) (pa_context *c, const char *buffer, void *userdata);
+pa_operation* pa_context_get_log(pa_context *c, pa_log_info_cb_t cb, void *userdata);
+
 /** @{ \name Cached Samples */
 
 /** Stores information about sample cache entries. Please note that this structure
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index fc9465b..6d1d717 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -186,7 +186,7 @@ static const struct command commands[] = {
     { "kill-client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
     { "kill-sink-input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
     { "kill-source-output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
-    { "set-log-target",          pa_cli_command_log_target,         "Change the log target (args: null,auto,syslog,stderr,file:PATH)", 2},
+    { "set-log-target",          pa_cli_command_log_target,         "Change the log target (args: null,ring,auto,syslog,stderr,file:PATH)", 2},
     { "set-log-level",           pa_cli_command_log_level,          "Change the log level (args: numeric level)", 2},
     { "set-log-meta",            pa_cli_command_log_meta,           "Show source code location in log messages (args: bool)", 2},
     { "set-log-time",            pa_cli_command_log_time,           "Show timestamps in log messages (args: bool)", 2},
@@ -1506,6 +1506,8 @@ static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf
 
     if (pa_streq(m, "null"))
         pa_log_set_target(PA_LOG_NULL);
+    else if (pa_streq(m, "ring"))
+        pa_log_set_target(PA_LOG_RING);
     else if (pa_streq(m, "syslog"))
         pa_log_set_target(PA_LOG_SYSLOG);
     else if (pa_streq(m, "stderr") || pa_streq(m, "auto")) {
diff --git a/src/pulsecore/llist.h b/src/pulsecore/llist.h
index 27f174a..aadd40e 100644
--- a/src/pulsecore/llist.h
+++ b/src/pulsecore/llist.h
@@ -31,6 +31,9 @@
 #define PA_LLIST_HEAD(t,name)                                           \
     t *name
 
+#define PA_STATIC_LLIST_HEAD(t,name)                                    \
+    static t *name = (t*) NULL;
+
 /* The pointers in the linked list's items. Use this in the item structure */
 #define PA_LLIST_FIELDS(t)                                              \
     t *next, *prev
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index 8eaef54..4338729 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -50,6 +50,7 @@
 #include <pulsecore/once.h>
 #include <pulsecore/ratelimit.h>
 #include <pulsecore/thread.h>
+#include <pulsecore/llist.h>
 
 #include "log.h"
 
@@ -265,6 +266,117 @@ static void init_defaults(void) {
     } PA_ONCE_END;
 }
 
+#define PA_LOG_SLOTS 200
+#define PA_LOG_SLOT_LENGTH 512
+
+static inline int next_slot(int nr) {
+    nr++;
+    if (nr >= PA_LOG_SLOTS)
+        nr = 0;
+    return nr;
+}
+
+static inline int prev_slot(int nr) {
+    nr--;
+    if (nr < 0)
+        nr = PA_LOG_SLOTS - 1;
+    return nr;
+}
+
+struct log_slot {
+    PA_LLIST_FIELDS(struct log_slot);
+
+    pthread_t tid;
+
+    int last_slot;
+
+    char slots[PA_LOG_SLOTS][PA_LOG_SLOT_LENGTH];
+    pa_usec_t timestamps[PA_LOG_SLOTS];
+
+    int loop_iter;      /* this field is used for log reading only */
+};
+
+PA_STATIC_LLIST_HEAD(struct log_slot, log_slots);
+static pa_static_mutex log_slots_mutex = PA_STATIC_MUTEX_INIT;
+
+static struct log_slot *get_current_thread_log_slots(void) {
+    pa_mutex *mutex;
+    pthread_t tid;
+    struct log_slot *slot, *new;
+
+    tid = pa_thread_get_tid(pa_thread_self());
+
+    mutex = pa_static_mutex_get(&log_slots_mutex, TRUE, TRUE);
+    pa_mutex_lock(mutex);
+    if (!log_slots) {
+        log_slots = pa_xnew0(struct log_slot, 1);
+        log_slots->tid = tid;
+        log_slots->last_slot = 0;
+        PA_LLIST_INIT(struct log_slot, log_slots);
+
+        pa_mutex_unlock(mutex);
+
+        return log_slots;
+    }
+
+    /* search for matching tid */
+    PA_LLIST_FOREACH(slot, log_slots) {
+        if (slot->tid == tid) {
+            pa_mutex_unlock(mutex);
+            return slot;
+        }
+    }
+
+    /* if not found, create new item */
+    new = pa_xnew0(struct log_slot, 1);
+    new->tid = tid;
+    new->last_slot = 0;
+
+    PA_LLIST_PREPEND(struct log_slot, log_slots, new);
+
+    pa_mutex_unlock(mutex);
+
+    return new;
+}
+
+void pa_log_get_strbuf(pa_strbuf *buf) {
+    pa_mutex *mutex;
+    struct log_slot *slot;
+    int i = 0;
+
+    mutex = pa_static_mutex_get(&log_slots_mutex, TRUE, TRUE);
+    pa_mutex_lock(mutex);
+
+    /* setup iterators */
+    PA_LLIST_FOREACH(slot, log_slots) {
+        slot->loop_iter = prev_slot(slot->last_slot);
+    }
+
+    /* extract at most PA_LOG_SLOTS logs */
+    while (i < PA_LOG_SLOTS) {
+        struct log_slot *max_slot = NULL;
+        pa_usec_t max_ts = 0;
+
+        PA_LLIST_FOREACH(slot, log_slots) {
+            pa_usec_t ts = slot->timestamps[slot->loop_iter];
+            if (ts > max_ts) {
+                max_ts = ts;
+                max_slot = slot;
+            }
+        }
+
+        if (!max_slot)
+            break;
+
+        pa_strbuf_puts(buf, max_slot->slots[max_slot->loop_iter]);
+        max_slot->loop_iter = prev_slot(max_slot->loop_iter);
+
+        i++;
+    }
+
+    pa_mutex_unlock(mutex);
+}
+
 void pa_log_levelv_meta(
         pa_log_level_t level,
         const char*file,
@@ -280,6 +392,8 @@ void pa_log_levelv_meta(
     pa_log_level_t _maximum_level;
     unsigned _show_backtrace;
     pa_log_flags_t _flags;
+    pa_usec_t ts = 0;
+    struct log_slot *slot = NULL;
 
     /* We don't use dynamic memory allocation here to minimize the hit
      * in RT threads */
@@ -300,6 +414,11 @@ void pa_log_levelv_meta(
         return;
     }
 
+    if (_target == PA_LOG_RING) {
+        ts = pa_rtclock_now();
+        slot = get_current_thread_log_slots();
+    }
+
     pa_vsnprintf(text, sizeof(text), format, ap);
 
     if ((_flags & PA_LOG_PRINT_META) && file && line > 0 && func)
@@ -355,6 +474,21 @@ void pa_log_levelv_meta(
             continue;
 
         switch (_target) {
+            case PA_LOG_RING: {
+                char *buffer;
+
+                slot->last_slot = next_slot(slot->last_slot);
+
+                slot->timestamps[slot->last_slot] = ts;
+
+                buffer = slot->slots[slot->last_slot];
+
+                if (_flags & PA_LOG_PRINT_LEVEL)
+                    pa_snprintf(buffer, PA_LOG_SLOT_LENGTH, "%s%c: %s%s%s\n", timestamp, level_to_char[level], location, t, pa_strempty(bt));
+                else
+                    pa_snprintf(buffer, PA_LOG_SLOT_LENGTH, "%s%s%s%s\n", timestamp, location, t, pa_strempty(bt));
+                break;
+            }
 
             case PA_LOG_STDERR: {
                 const char *prefix = "", *suffix = "", *grey = "";
diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
index 8dd056b..d6560ff 100644
--- a/src/pulsecore/log.h
+++ b/src/pulsecore/log.h
@@ -26,6 +26,7 @@
 #include <stdarg.h>
 #include <stdlib.h>
 
+#include <pulsecore/strbuf.h>
 #include <pulsecore/macro.h>
 #include <pulse/gccmacro.h>
 
@@ -37,6 +38,7 @@ typedef enum pa_log_target {
     PA_LOG_SYSLOG,
     PA_LOG_NULL,    /* to /dev/null */
     PA_LOG_FD,      /* to a file descriptor, e.g. a char device */
+    PA_LOG_RING,    /* to a ring buffer */
     PA_LOG_TARGET_MAX
 } pa_log_target_t;
 
@@ -142,4 +144,6 @@ LOG_FUNC(error, PA_LOG_ERROR)
 
 pa_bool_t pa_log_ratelimit(pa_log_level_t level);
 
+void pa_log_get_strbuf(pa_strbuf *buf);
+
 #endif
diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h
index 8fde023..1927de2 100644
--- a/src/pulsecore/native-common.h
+++ b/src/pulsecore/native-common.h
@@ -46,6 +46,7 @@ enum {
     PA_COMMAND_LOOKUP_SOURCE,
     PA_COMMAND_DRAIN_PLAYBACK_STREAM,
     PA_COMMAND_STAT,
+    PA_COMMAND_GET_LOG,
     PA_COMMAND_GET_PLAYBACK_LATENCY,
     PA_COMMAND_CREATE_UPLOAD_STREAM,
     PA_COMMAND_DELETE_UPLOAD_STREAM,
diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c
index 9a9ef4e..ed88f73 100644
--- a/src/pulsecore/pdispatch.c
+++ b/src/pulsecore/pdispatch.c
@@ -64,6 +64,7 @@ static const char *command_names[PA_COMMAND_MAX] = {
     [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE",
     [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM",
     [PA_COMMAND_STAT] = "STAT",
+    [PA_COMMAND_GET_LOG] = "GET_LOG",
     [PA_COMMAND_GET_PLAYBACK_LATENCY] = "GET_PLAYBACK_LATENCY",
     [PA_COMMAND_CREATE_UPLOAD_STREAM] = "CREATE_UPLOAD_STREAM",
     [PA_COMMAND_DELETE_UPLOAD_STREAM] = "DELETE_UPLOAD_STREAM",
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index c24254a..f526b2d 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -262,6 +262,7 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
+static void command_get_log(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
@@ -309,6 +310,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
     [PA_COMMAND_LOOKUP_SINK] = command_lookup,
     [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
     [PA_COMMAND_STAT] = command_stat,
+    [PA_COMMAND_GET_LOG] = command_get_log,
     [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
     [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
     [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
@@ -2786,6 +2788,31 @@ static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
     pa_pstream_send_tagstruct(c->pstream, reply);
 }
 
+static void command_get_log(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+    pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
+    pa_tagstruct *reply;
+    pa_strbuf *strbuf;
+
+    pa_native_connection_assert_ref(c);
+    pa_assert(t);
+
+    if (!pa_tagstruct_eof(t)) {
+        protocol_error(c);
+        return;
+    }
+
+    CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
+
+    reply = reply_new(tag);
+
+    strbuf = pa_strbuf_new();
+    pa_log_get_strbuf(strbuf);
+    pa_tagstruct_put_strbuf(reply, strbuf);
+    pa_strbuf_free(strbuf);
+
+    pa_pstream_send_tagstruct(c->pstream, reply);
+}
+
 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
     pa_tagstruct *reply;
diff --git a/src/pulsecore/strlist.c b/src/pulsecore/strlist.c
index 4c06fee..8a48e8c 100644
--- a/src/pulsecore/strlist.c
+++ b/src/pulsecore/strlist.c
@@ -27,7 +27,6 @@
 
 #include <pulse/xmalloc.h>
 
-#include <pulsecore/strbuf.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 
diff --git a/src/pulsecore/tagstruct.c b/src/pulsecore/tagstruct.c
index a0f1f10..7b01fce 100644
--- a/src/pulsecore/tagstruct.c
+++ b/src/pulsecore/tagstruct.c
@@ -95,6 +95,12 @@ static void extend(pa_tagstruct*t, size_t l) {
     t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100);
 }
 
+void pa_tagstruct_put_strbuf(pa_tagstruct*t, pa_strbuf *s) {
+    char *buf = pa_strbuf_tostring(s);
+    pa_tagstruct_puts(t, buf);
+    pa_xfree(buf);
+}
+
 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
     size_t l;
     pa_assert(t);
diff --git a/src/pulsecore/tagstruct.h b/src/pulsecore/tagstruct.h
index 5f729bc..4d77cd1 100644
--- a/src/pulsecore/tagstruct.h
+++ b/src/pulsecore/tagstruct.h
@@ -33,6 +33,7 @@
 #include <pulse/proplist.h>
 
 #include <pulsecore/macro.h>
+#include <pulsecore/strbuf.h>
 
 typedef struct pa_tagstruct pa_tagstruct;
 
@@ -71,6 +72,7 @@ const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l);
 
 void pa_tagstruct_put(pa_tagstruct *t, ...);
 
+void pa_tagstruct_put_strbuf(pa_tagstruct*t, pa_strbuf *s);
 void pa_tagstruct_puts(pa_tagstruct*t, const char *s);
 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c);
 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i);
diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c
index 3f4ae5c..c5395fe 100644
--- a/src/pulsecore/thread-posix.c
+++ b/src/pulsecore/thread-posix.c
@@ -206,6 +206,10 @@ const char *pa_thread_get_name(pa_thread *t) {
     return t->name;
 }
 
+int pa_thread_get_tid(pa_thread *t) {
+    return (int)t->id;
+}
+
 void pa_thread_yield(void) {
 #ifdef HAVE_PTHREAD_YIELD
     pthread_yield();
diff --git a/src/pulsecore/thread-win32.c b/src/pulsecore/thread-win32.c
index 89c8c46..fcbf43b 100644
--- a/src/pulsecore/thread-win32.c
+++ b/src/pulsecore/thread-win32.c
@@ -144,6 +144,10 @@ const char *pa_thread_get_name(pa_thread *t) {
     return NULL;
 }
 
+int pa_thread_get_tid(pa_thread *t) {
+    return (int)t->thread;
+}
+
 void pa_thread_yield(void) {
     Sleep(0);
 }
diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h
index 9cabb89..53bf6d6 100644
--- a/src/pulsecore/thread.h
+++ b/src/pulsecore/thread.h
@@ -50,6 +50,8 @@ void pa_thread_set_data(pa_thread *t, void *userdata);
 const char *pa_thread_get_name(pa_thread *t);
 void pa_thread_set_name(pa_thread *t, const char *name);
 
+int pa_thread_get_tid(pa_thread *t);
+
 typedef struct pa_tls pa_tls;
 
 pa_tls* pa_tls_new(pa_free_cb_t free_cb);
diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 5346b94..d598db1 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -94,6 +94,7 @@ static enum {
     NONE,
     EXIT,
     STAT,
+    LOG,
     INFO,
     UPLOAD_SAMPLE,
     PLAY_SAMPLE,
@@ -165,6 +166,12 @@ static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata)
     complete_action();
 }
 
+static void get_log_callback(pa_context *c, const char *buf, void *userdata) {
+    if (buf != NULL)
+        printf("%s\n", buf);
+    complete_action();
+}
+
 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
     char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
 
@@ -1107,6 +1114,10 @@ static void context_state_callback(pa_context *c, void *userdata) {
                         break;
                     actions++;
 
+                case LOG:
+                    pa_operation_unref(pa_context_get_log(c, get_log_callback, NULL));
+                    break;
+
                 case INFO:
                     pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
                     break;
@@ -1367,6 +1378,7 @@ static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flag
 static void help(const char *argv0) {
 
     printf("%s %s %s\n",    argv0, _("[options]"), "stat [short]");
+    printf("%s %s %s\n",    argv0, _("[options]"), "log");
     printf("%s %s %s\n",    argv0, _("[options]"), "info");
     printf("%s %s %s %s\n", argv0, _("[options]"), "list [short]", _("[TYPE]"));
     printf("%s %s %s\n",    argv0, _("[options]"), "exit");
@@ -1468,6 +1480,9 @@ int main(int argc, char *argv[]) {
             if (optind+1 < argc && pa_streq(argv[optind+1], "short"))
                 short_list_format = TRUE;
 
+        } else if (pa_streq(argv[optind], "log")) {
+            action = LOG;
+
         } else if (pa_streq(argv[optind], "info"))
             action = INFO;
 
-- 
1.7.7.6



More information about the pulseaudio-discuss mailing list