Commit 083f5c0c authored by Ed "oddsock" Zaleski's avatar Ed "oddsock" Zaleski

this patch adds a playlist log to icecast. This can be used to maintain an...

this patch adds a playlist log to icecast.  This can be used to maintain an audit trail of metadata that comes through icecast.  The format of the log file may be changed in the future as we decide on a good format.

svn path=/icecast/trunk/icecast/; revision=8205
parent d7a30dc0
......@@ -127,6 +127,7 @@
<logging>
<accesslog>access.log</accesslog>
<errorlog>error.log</errorlog>
<!-- <playlistlog>playlist.log</playlistlog> -->
<loglevel>4</loglevel> <!-- 4 Debug, 3 Info, 2 Warn, 1 Error -->
</logging>
......
......@@ -423,6 +423,7 @@ Aliases are used to provide a way to create multiple mountpoints that refer to t
&lt;logging&gt;
&lt;accesslog&gt;access.log&lt;/accesslog&gt;
&lt;errorlog&gt;error.log&lt;/errorlog&gt;
&lt;playlistlog&gt;playlist.log&lt;/playlistlog&gt;
&lt;loglevel&gt;4&lt;/loglevel&gt; &lt;-- 4 Debug, 3 Info, 2 Warn, 1 Error --&gt;
&lt;/logging&gt;
</pre>
......@@ -438,6 +439,10 @@ Into this file, all requests made to the icecast2 will be logged. This file is
<div class="indentedbox">
All icecast generated log messages will be written to this file. If the loglevel is set too high (Debug for instance) then this file can grow fairly large over time. Currently, there is no log-rotation implemented.
</div>
<h4>playlistlog</h4>
<div class="indentedbox">
Into this file, a log of all metadata for each mountpoint will be written. The format of the logfile will most likely change over time as we narrow in on a standard format for this. Currently, the file is pipe delimited. This option is optional and can be removed entirely from the config file.
</div>
<h4>loglevel</h4>
<div class="indentedbox">
Indicates what messages are logged by icecast. Log messages are categorized into one of 4 types, Debug, Info, Warn, and Error.<br /><br />The following mapping can be used to set the appropraite value :
......
......@@ -847,6 +847,9 @@ static void command_metadata(client_t *client, source_t *source)
source->mount, value);
stats_event(source->mount, "title", value);
/* At this point, we assume that the metadata passed in
is encoded in UTF-8 */
logging_playlist(source->mount, value, source->listeners);
/* If we get an update on the mountpoint, force a
yp touch */
yp_touch (source->mount);
......
......@@ -42,6 +42,7 @@
#define CONFIG_DEFAULT_FILESERVE 1
#define CONFIG_DEFAULT_TOUCH_FREQ 5
#define CONFIG_DEFAULT_HOSTNAME "localhost"
#define CONFIG_DEFAULT_PLAYLIST_LOG NULL
#define CONFIG_DEFAULT_ACCESS_LOG "access.log"
#define CONFIG_DEFAULT_ERROR_LOG "error.log"
#define CONFIG_DEFAULT_LOG_LEVEL 4
......@@ -149,6 +150,8 @@ void config_clear(ice_config_t *c)
xmlFree(c->adminroot_dir);
if (c->pidfile)
xmlFree(c->pidfile);
if (c->playlist_log && c->playlist_log != CONFIG_DEFAULT_PLAYLIST_LOG)
xmlFree(c->playlist_log);
if (c->access_log && c->access_log != CONFIG_DEFAULT_ACCESS_LOG)
xmlFree(c->access_log);
if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG)
......@@ -330,6 +333,7 @@ static void _set_defaults(ice_config_t *configuration)
configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR;
configuration->adminroot_dir = CONFIG_DEFAULT_ADMINROOT_DIR;
configuration->playlist_log = CONFIG_DEFAULT_PLAYLIST_LOG;
configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG;
configuration->error_log = CONFIG_DEFAULT_ERROR_LOG;
configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
......@@ -840,6 +844,9 @@ static void _parse_logging(xmlDocPtr doc, xmlNodePtr node,
} else if (strcmp(node->name, "errorlog") == 0) {
if (configuration->error_log && configuration->error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(configuration->error_log);
configuration->error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (strcmp(node->name, "playlistlog") == 0) {
if (configuration->playlist_log && configuration->playlist_log != CONFIG_DEFAULT_PLAYLIST_LOG) xmlFree(configuration->playlist_log);
configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (strcmp(node->name, "loglevel") == 0) {
char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->loglevel = atoi(tmp);
......
......@@ -128,6 +128,7 @@ typedef struct ice_config_tag
char *access_log;
char *error_log;
char *playlist_log;
int loglevel;
int chroot;
......
......@@ -127,7 +127,10 @@ static refbuf_t *format_vorbis_get_buffer (source_t *source)
{
int result;
ogg_packet op;
char *tag;
char *title_tag;
char *artist_tag;
char *metadata = NULL;
int metadata_len = 0;
refbuf_t *refbuf, *header;
char *data;
format_plugin_t *self = source->format;
......@@ -202,13 +205,39 @@ static refbuf_t *format_vorbis_get_buffer (source_t *source)
DEBUG0 ("doing stats");
/* put known comments in the stats */
tag = vorbis_comment_query(&state->vc, "TITLE", 0);
if (tag) stats_event(source->mount, "title", tag);
title_tag = vorbis_comment_query(&state->vc, "TITLE", 0);
if (title_tag) stats_event(source->mount, "title", title_tag);
else stats_event(source->mount, "title", "unknown");
tag = vorbis_comment_query(&state->vc, "ARTIST", 0);
if (tag) stats_event(source->mount, "artist", tag);
artist_tag = vorbis_comment_query(&state->vc, "ARTIST", 0);
if (artist_tag) stats_event(source->mount, "artist", artist_tag);
else stats_event(source->mount, "artist", "unknown");
metadata = NULL;
if (artist_tag) {
if (title_tag) {
metadata_len = strlen(artist_tag) + strlen(title_tag) +
strlen(" - ") + 1;
metadata = (char *)calloc(1, metadata_len);
sprintf(metadata, "%s - %s", artist_tag, title_tag);
}
else {
metadata_len = strlen(artist_tag) + 1;
metadata = (char *)calloc(1, metadata_len);
sprintf(metadata, "%s", artist_tag);
}
}
else {
if (title_tag) {
metadata_len = strlen(title_tag) + 1;
metadata = (char *)calloc(1, metadata_len);
sprintf(metadata, "%s", title_tag);
}
}
if (metadata) {
logging_playlist(source->mount, metadata, source->listeners);
free(metadata);
metadata = NULL;
}
/* don't need these now */
ogg_stream_clear(&state->os);
vorbis_comment_clear(&state->vc);
......
......@@ -37,6 +37,7 @@
/* the global log descriptors */
int errorlog = 0;
int accesslog = 0;
int playlistlog = 0;
#ifdef _WIN32
/* Since strftime's %z option on win32 is different, we need
......@@ -153,6 +154,37 @@ void logging_access(client_t *client)
user_agent,
stayed);
}
/* This function will provide a log of metadata for each
mountpoint. The metadata *must* be in UTF-8, and thus
you can assume that the log itself is UTF-8 encoded */
void logging_playlist(char *mount, char *metadata, long listeners)
{
char datebuf[128];
struct tm thetime;
time_t now;
if (playlistlog == -1) {
return;
}
now = time(NULL);
localtime_r (&now, &thetime);
/* build the data */
#ifdef _WIN32
memset(datebuf, '\000', sizeof(datebuf));
get_clf_time(datebuf, sizeof(datebuf)-1, &thetime);
#else
strftime (datebuf, sizeof(datebuf), LOGGING_FORMAT_CLF, &thetime);
#endif
/* This format MAY CHANGE OVER TIME. We are looking into finding a good
standard format for this, if you have any ideas, please let us know */
log_write_direct (playlistlog, "%s|%s|%d|%s",
datebuf,
mount,
listeners,
metadata);
}
......@@ -174,4 +206,12 @@ void restart_logging (ice_config_t *config)
log_set_filename (accesslog, fn_error);
log_reopen (accesslog);
}
if (config->playlist_log)
{
char fn_error[FILENAME_MAX];
snprintf (fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->playlist_log);
log_set_filename (playlistlog, fn_error);
log_reopen (playlistlog);
}
}
......@@ -20,6 +20,7 @@
extern int errorlog;
extern int accesslog;
extern int playlistlog;
/* these are all ERRORx and WARNx where _x_ is the number of parameters
** it takes. it turns out most other copmilers don't have support for
......@@ -88,6 +89,7 @@ extern int accesslog;
#define LOGGING_FORMAT_CLF "%d/%b/%Y:%H:%M:%S %z"
void logging_access(client_t *client);
void logging_playlist(char *mount, char *metadata, long listeners);
void restart_logging (ice_config_t *config);
#endif /* __LOGGING_H__ */
......
......@@ -87,6 +87,7 @@ static void _stop_logging(void)
{
log_close(errorlog);
log_close(accesslog);
log_close(playlistlog);
}
static void _initialize_subsystems(void)
......@@ -178,6 +179,7 @@ static int _start_logging(void)
{
char fn_error[FILENAME_MAX];
char fn_access[FILENAME_MAX];
char fn_playlist[FILENAME_MAX];
char buf[1024];
int log_to_stderr;
......@@ -219,9 +221,26 @@ static int _start_logging(void)
strerror(errno));
_fatal_error(buf);
}
if(config->playlist_log) {
snprintf(fn_playlist, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->playlist_log);
playlistlog = log_open(fn_playlist);
if (playlistlog < 0) {
buf[sizeof(buf)-1] = 0;
snprintf(buf, sizeof(buf)-1,
"FATAL: could not open playlist logging (%s): %s",
log_to_stderr?"standard error":fn_playlist,
strerror(errno));
_fatal_error(buf);
}
log_to_stderr = 0;
} else {
playlistlog = -1;
}
log_set_level(errorlog, config->loglevel);
log_set_level(accesslog, 4);
log_set_level(playlistlog, 4);
if (errorlog >= 0 && accesslog >= 0) return 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment