1 /*****************************************************************************
2 * logger.c : file logging plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2002-2008 the VideoLAN team
7 * Authors: Samuel Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_interface.h>
36 #include <vlc_charset.h>
42 # include <android/log.h>
45 #define LOG_FILE_TEXT "vlc-log.txt"
46 #define LOG_FILE_HTML "vlc-log.html"
48 #define TEXT_HEADER "\xEF\xBB\xBF-- logger module started --\n"
49 #define TEXT_FOOTER "-- logger module stopped --\n"
52 "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n" \
53 " \"http://www.w3.org/TR/html4/strict.dtd\">\n" \
56 " <title>vlc log</title>\n" \
57 " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" \
59 " <body style=\"background-color: #000000; color: #aaaaaa;\">\n" \
61 " <strong>-- logger module started --</strong>\n"
63 " <strong>-- logger module stopped --</strong>\n" \
72 /*****************************************************************************
73 * intf_sys_t: description and status of log interface
74 *****************************************************************************/
82 /*****************************************************************************
84 *****************************************************************************/
85 static int Open ( vlc_object_t
* );
86 static void Close ( vlc_object_t
* );
88 static void TextPrint(void *, int, const vlc_log_t
*, const char *, va_list);
89 static void HtmlPrint(void *, int, const vlc_log_t
*, const char *, va_list);
91 static void SyslogPrint(void *, int, const vlc_log_t
*, const char *, va_list);
94 static void AndroidPrint(void *, int, const vlc_log_t
*, const char *, va_list);
97 /*****************************************************************************
99 *****************************************************************************/
100 static const char *const mode_list
[] = { "text", "html"
108 static const char *const mode_list_text
[] = { N_("Text"), "HTML"
117 #define LOGMODE_TEXT N_("Log format")
118 #define LOGMODE_LONGTEXT N_("Specify the logging format.")
121 #define SYSLOG_IDENT_TEXT N_("Syslog ident")
122 #define SYSLOG_IDENT_LONGTEXT N_("Set the ident that VLC would use when " \
123 "logging to syslog.")
125 #define SYSLOG_FACILITY_TEXT N_("Syslog facility")
126 #define SYSLOG_FACILITY_LONGTEXT N_("Select the syslog facility where logs " \
127 "will be forwarded.")
129 /* First in list is the default facility used. */
130 #define DEFINE_SYSLOG_FACILITY \
131 DEF( "user", LOG_USER ), \
132 DEF( "daemon", LOG_DAEMON ), \
133 DEF( "local0", LOG_LOCAL0 ), \
134 DEF( "local1", LOG_LOCAL1 ), \
135 DEF( "local2", LOG_LOCAL2 ), \
136 DEF( "local3", LOG_LOCAL3 ), \
137 DEF( "local4", LOG_LOCAL4 ), \
138 DEF( "local5", LOG_LOCAL5 ), \
139 DEF( "local6", LOG_LOCAL6 ), \
140 DEF( "local7", LOG_LOCAL7 )
142 #define DEF( a, b ) a
143 static const char *const fac_name
[] = { DEFINE_SYSLOG_FACILITY
};
145 #define DEF( a, b ) b
146 static const int fac_number
[] = { DEFINE_SYSLOG_FACILITY
};
148 enum { fac_entries
= sizeof(fac_name
)/sizeof(fac_name
[0]) };
149 #undef DEFINE_SYSLOG_FACILITY
153 #define LOGVERBOSE_TEXT N_("Verbosity")
154 #define LOGVERBOSE_LONGTEXT N_("Select the verbosity to use for log or -1 to " \
155 "use the same verbosity given by --verbose.")
158 set_shortname( N_( "Logging" ) )
159 set_description( N_("File logging") )
161 set_category( CAT_ADVANCED
)
162 set_subcategory( SUBCAT_ADVANCED_MISC
)
164 add_savefile( "logfile", NULL
,
165 N_("Log filename"), N_("Specify the log filename."), false )
166 add_string( "logmode", "text", LOGMODE_TEXT
, LOGMODE_LONGTEXT
,
168 change_string_list( mode_list
, mode_list_text
)
170 add_string( "syslog-ident", "vlc", SYSLOG_IDENT_TEXT
,
171 SYSLOG_IDENT_LONGTEXT
, true )
172 add_string( "syslog-facility", fac_name
[0], SYSLOG_FACILITY_TEXT
,
173 SYSLOG_FACILITY_LONGTEXT
, true )
174 change_string_list( fac_name
, fac_name
)
176 add_integer( "log-verbose", -1, LOGVERBOSE_TEXT
, LOGVERBOSE_LONGTEXT
,
179 add_obsolete_string( "rrd-file" )
181 set_capability( "interface", 0 )
182 set_callbacks( Open
, Close
)
185 /*****************************************************************************
186 * Open: initialize and create stuff
187 *****************************************************************************/
188 static int Open( vlc_object_t
*p_this
)
190 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
194 msg_Info( p_intf
, "using logger." );
196 /* Allocate instance and initialize some members */
197 p_sys
= p_intf
->p_sys
= (intf_sys_t
*)malloc( sizeof( intf_sys_t
) );
201 p_sys
->p_file
= NULL
;
202 vlc_log_cb cb
= TextPrint
;
203 const char *filename
= LOG_FILE_TEXT
, *header
= TEXT_HEADER
;
204 p_sys
->footer
= TEXT_FOOTER
;
206 char *mode
= var_InheritString( p_intf
, "logmode" );
209 if( !strcmp( mode
, "html" ) )
211 p_sys
->footer
= HTML_FOOTER
;
212 header
= HTML_HEADER
;
216 else if( !strcmp( mode
, "syslog" ) )
220 else if( !strcmp( mode
, "android" ) )
223 else if( strcmp( mode
, "text" ) )
224 msg_Warn( p_intf
, "invalid log mode `%s', using `text'", mode
);
229 if( cb
== SyslogPrint
)
232 char *psz_facility
= var_InheritString( p_intf
, "syslog-facility" );
236 for( size_t i
= 0; i
< fac_entries
; ++i
)
238 if( !strcmp( psz_facility
, fac_name
[i
] ) )
240 i_facility
= fac_number
[i
];
247 msg_Warn( p_intf
, "invalid syslog facility `%s', using `%s'",
248 psz_facility
, fac_name
[0] );
249 i_facility
= fac_number
[0];
251 free( psz_facility
);
255 msg_Warn( p_intf
, "no syslog facility specified, using `%s'",
257 i_facility
= fac_number
[0];
260 char *psz_syslog_ident
= var_InheritString( p_intf
, "syslog-ident" );
261 if (unlikely(psz_syslog_ident
== NULL
))
267 p_sys
->ident
= psz_syslog_ident
;
268 openlog( p_sys
->ident
, LOG_PID
|LOG_NDELAY
, i_facility
);
270 p_sys
->p_file
= NULL
;
275 if( cb
== AndroidPrint
)
282 char *psz_file
= var_InheritString( p_intf
, "logfile" );
286 # define LOG_DIR "Library/Logs"
287 char *home
= config_GetUserDir(VLC_HOME_DIR
);
289 || asprintf( &psz_file
, "%s/"LOG_DIR
"/%s", home
,
295 msg_Warn( p_intf
, "no log filename provided, using `%s'",
301 /* Open the log file and remove any buffering for the stream */
302 msg_Dbg( p_intf
, "opening logfile `%s'", filename
);
303 p_sys
->p_file
= vlc_fopen( filename
, "at" );
305 if( p_sys
->p_file
== NULL
)
307 msg_Err( p_intf
, "error opening logfile `%s': %m", filename
);
311 setvbuf( p_sys
->p_file
, NULL
, _IONBF
, 0 );
312 fputs( header
, p_sys
->p_file
);
315 vlc_LogSet( p_intf
->p_libvlc
, cb
, p_intf
);
319 /*****************************************************************************
320 * Close: destroy interface stuff
321 *****************************************************************************/
322 static void Close( vlc_object_t
*p_this
)
324 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
325 intf_sys_t
*p_sys
= p_intf
->p_sys
;
327 /* Flush the queue and unsubscribe from the message queue */
328 vlc_LogSet( p_intf
->p_libvlc
, NULL
, NULL
);
330 /* Close the log file */
332 if( p_sys
->p_file
== NULL
)
335 free( p_sys
->ident
);
341 fputs( p_sys
->footer
, p_sys
->p_file
);
342 fclose( p_sys
->p_file
);
345 /* Destroy structure */
349 static bool IgnoreMessage( intf_thread_t
*p_intf
, int type
)
351 /* TODO: cache value... */
352 int verbosity
= var_InheritInteger( p_intf
, "log-verbose" );
354 verbosity
= var_InheritInteger( p_intf
, "verbose" );
356 return verbosity
< 0 || verbosity
< (type
- VLC_MSG_ERR
);
363 static const char ppsz_type
[4][9] = {
371 static const android_LogPriority prioritytype
[4] = {
378 static void AndroidPrint( void *opaque
, int type
, const vlc_log_t
*item
,
379 const char *fmt
, va_list ap
)
382 intf_thread_t
*p_intf
= opaque
;
384 if( IgnoreMessage( p_intf
, type
) )
387 int canc
= vlc_savecancel();
388 __android_log_vprint(prioritytype
[type
], "VLC", fmt
, ap
);
389 vlc_restorecancel( canc
);
393 static void TextPrint( void *opaque
, int type
, const vlc_log_t
*item
,
394 const char *fmt
, va_list ap
)
396 intf_thread_t
*p_intf
= opaque
;
397 FILE *stream
= p_intf
->p_sys
->p_file
;
399 if( IgnoreMessage( p_intf
, type
) )
402 int canc
= vlc_savecancel();
404 fprintf( stream
, "%s%s: ", item
->psz_module
, ppsz_type
[type
] );
405 vfprintf( stream
, fmt
, ap
);
406 putc_unlocked( '\n', stream
);
407 funlockfile( stream
);
408 vlc_restorecancel( canc
);
412 static void SyslogPrint( void *opaque
, int type
, const vlc_log_t
*item
,
413 const char *fmt
, va_list ap
)
415 static const int i_prio
[4] = { LOG_INFO
, LOG_ERR
, LOG_WARNING
, LOG_DEBUG
};
417 intf_thread_t
*p_intf
= opaque
;
419 int i_priority
= i_prio
[type
];
421 if( IgnoreMessage( p_intf
, type
)
422 || unlikely(vasprintf( &str
, fmt
, ap
) == -1) )
425 int canc
= vlc_savecancel();
426 if( item
->psz_header
!= NULL
)
427 syslog( i_priority
, "[%s] %s%s: %s", item
->psz_header
,
428 item
->psz_module
, ppsz_type
[type
], str
);
430 syslog( i_priority
, "%s%s: %s",
431 item
->psz_module
, ppsz_type
[type
], str
);
432 vlc_restorecancel( canc
);
437 static void HtmlPrint( void *opaque
, int type
, const vlc_log_t
*item
,
438 const char *fmt
, va_list ap
)
440 static const unsigned color
[4] = {
441 0xffffff, 0xff6666, 0xffff66, 0xaaaaaa,
444 intf_thread_t
*p_intf
= opaque
;
445 FILE *stream
= p_intf
->p_sys
->p_file
;
447 if( IgnoreMessage( p_intf
, type
) )
450 int canc
= vlc_savecancel();
452 fprintf( stream
, "%s%s: <span style=\"color: #%06x\">",
453 item
->psz_module
, ppsz_type
[type
], color
[type
] );
454 /* FIXME: encode special ASCII characters */
455 vfprintf( stream
, fmt
, ap
);
456 fputs( "</span>\n", stream
);
457 funlockfile( stream
);
458 vlc_restorecancel( canc
);