diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index c030bcc1b2..0109c5e019 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -443,6 +443,11 @@ Program Behavior ``bestvideo+bestaudio``. (Default: ``best``) +``--log-file=`` + Opens the given path for writing, and print log messages to it. Existing + files will be truncated. The log level always corresponds to ``-v``, + regardless of terminal verbosity levels. + Video ----- diff --git a/common/msg.c b/common/msg.c index e117589873..33c8d419df 100644 --- a/common/msg.c +++ b/common/msg.c @@ -60,6 +60,7 @@ struct mp_log_root { bool force_stderr; struct mp_log_buffer **buffers; int num_buffers; + FILE *log_file; FILE *stats_file; // --- semi-atomic access bool mute; @@ -122,6 +123,8 @@ static void update_loglevel(struct mp_log *log) } for (int n = 0; n < log->root->num_buffers; n++) log->level = MPMAX(log->level, log->root->buffers[n]->level); + if (log->root->log_file) + log->level = MPMAX(log->level, MSGL_V); if (log->root->stats_file) log->level = MPMAX(log->level, MSGL_STATS); atomic_store(&log->reload_counter, atomic_load(&log->root->reload_counter)); @@ -278,6 +281,19 @@ static void print_terminal_line(struct mp_log *log, int lev, char *text) fflush(stream); } +static void write_log_file(struct mp_log *log, int lev, char *text) +{ + struct mp_log_root *root = log->root; + + if (lev > MSGL_V || !root->log_file) + return; + + fprintf(root->log_file, "[%8.3f][%c][%s] %s", + (mp_time_us() - MP_START_TIME) / 1e6, + mp_log_levels[lev][0], + log->verbose_prefix, text); +} + static void write_msg_to_buffers(struct mp_log *log, int lev, char *text) { struct mp_log_root *root = log->root; @@ -356,6 +372,7 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) char saved = next[0]; next[0] = '\0'; print_terminal_line(log, lev, text); + write_log_file(log, lev, text); write_msg_to_buffers(log, lev, text); next[0] = saved; text = next; @@ -461,6 +478,9 @@ void mp_msg_update_msglevels(struct mpv_global *global) talloc_free(root->msglevels); root->msglevels = talloc_strdup(root, global->opts->msglevels); + if (!root->log_file && opts->log_file && opts->log_file[0]) + root->log_file = fopen(opts->log_file, "wb"); + atomic_fetch_add(&root->reload_counter, 1); pthread_mutex_unlock(&mp_msg_lock); } @@ -484,6 +504,8 @@ void mp_msg_uninit(struct mpv_global *global) struct mp_log_root *root = global->log->root; if (root->stats_file) fclose(root->stats_file); + if (root->log_file) + fclose(root->log_file); talloc_free(root); global->log = NULL; } diff --git a/options/options.c b/options/options.c index 1748b3293c..1541f6f323 100644 --- a/options/options.c +++ b/options/options.c @@ -109,6 +109,7 @@ const m_option_t mp_opts[] = { .type = &m_option_type_msglevels), OPT_STRING("dump-stats", dump_stats, CONF_GLOBAL | CONF_PRE_PARSE), OPT_FLAG("msg-color", msg_color, CONF_GLOBAL | CONF_PRE_PARSE), + OPT_STRING("log-file", log_file, CONF_GLOBAL | CONF_PRE_PARSE), OPT_FLAG("msg-module", msg_module, CONF_GLOBAL), OPT_FLAG("msg-time", msg_time, CONF_GLOBAL), #ifdef _WIN32 diff --git a/options/options.h b/options/options.h index 00b4b588dd..8313ce1448 100644 --- a/options/options.h +++ b/options/options.h @@ -60,6 +60,7 @@ typedef struct MPOpts { int msg_color; int msg_module; int msg_time; + char *log_file; char **reset_options; char **script_files; diff --git a/osdep/timer.c b/osdep/timer.c index 123a78c850..7c57e1ef1c 100644 --- a/osdep/timer.c +++ b/osdep/timer.c @@ -38,7 +38,7 @@ static void do_timer_init(void) // Arbitrary additional offset to avoid confusing relative/absolute times. // Also,we rule that the timer never returns 0 (so default-initialized // time values will be always in the past). - raw_time_offset -= 10000000; + raw_time_offset -= MP_START_TIME; } void mp_time_init(void) diff --git a/osdep/timer.h b/osdep/timer.h index bc0e5252c9..2bef4130df 100644 --- a/osdep/timer.h +++ b/osdep/timer.h @@ -38,6 +38,8 @@ uint64_t mp_raw_time_us(void); // Sleep in microseconds. void mp_sleep_us(int64_t us); +#define MP_START_TIME 10000000 + // Return the amount of time that has passed since the last call, in // microseconds. *t is used to calculate the time that has passed by storing // the current time in it. If *t is 0, the call will return 0. (So that the