1
0
Fork 0
icecast-server/src/logging.c

281 lines
7.6 KiB
C

/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
* Michael Smith <msmith@xiph.org>,
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2011-2020, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "common/thread/thread.h"
#include "common/httpp/httpp.h"
#include "logging.h"
#include "connection.h"
#include "refbuf.h"
#include "client.h"
#include "compat.h"
#include "cfgfile.h"
#include "util.h"
#define CATMODULE "logging"
#ifdef _WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
/* the global log descriptors */
int errorlog = 0;
int accesslog = 0;
int playlistlog = 0;
int logging_str2logid(const char *str)
{
if (!str)
return -1;
if (!strcmp(str, "error")) {
return errorlog;
} else if (!strcmp(str, "access")) {
return accesslog;
} else if (!strcmp(str, "playlist")) {
return playlistlog;
}
return -1;
}
#ifdef _WIN32
/* Since strftime's %z option on win32 is different, we need
to go through a few loops to get the same info as %z */
int get_clf_time (char *buffer, unsigned len, struct tm *t)
{
char sign;
char timezone_string[7];
struct tm gmt;
time_t time1 = time(NULL);
int time_days, time_hours, time_tz;
int tempnum1, tempnum2;
struct tm *thetime;
time_t now;
#if !defined(_WIN32)
thetime = gmtime_r(&time1, &gmt)
#else
/* gmtime() on W32 breaks POSIX and IS thread-safe (uses TLS) */
thetime = gmtime (&time1);
if (thetime)
memcpy (&gmt, thetime, sizeof (gmt));
#endif
/* FIXME: bail out if gmtime* returns NULL */
if (!thetime) {
snprintf(buffer, len, "<<BAD TIMESTAMP>>");
return 0;
}
time_days = t->tm_yday - gmt.tm_yday;
if (time_days < -1) {
tempnum1 = 24;
}
else {
tempnum1 = 1;
}
if (tempnum1 < time_days) {
tempnum2 = -24;
}
else {
tempnum2 = time_days*24;
}
time_hours = (tempnum2 + t->tm_hour - gmt.tm_hour);
time_tz = time_hours * 60 + t->tm_min - gmt.tm_min;
if (time_tz < 0) {
sign = '-';
time_tz = -time_tz;
}
else {
sign = '+';
}
snprintf(timezone_string, sizeof(timezone_string), " %c%.2d%.2d", sign, time_tz / 60, time_tz % 60);
now = time(NULL);
thetime = localtime(&now);
strftime(buffer, len - sizeof(timezone_string), "%d/%b/%Y:%H:%M:%S", thetime);
strcat(buffer, timezone_string);
return 1;
}
#endif
/*
** ADDR IDENT USER DATE REQUEST CODE BYTES REFERER AGENT [TIME]
**
** ADDR = client->con->ip
** IDENT = always - , we don't support it because it's useless
** USER = client->username
** DATE = _make_date(client->con->con_time)
** REQUEST = build from client->parser
** CODE = client->respcode
** BYTES = client->con->sent_bytes
** REFERER = get from client->parser
** AGENT = get from client->parser
** TIME = timing_get_time() - client->con->con_time
*/
void logging_access(client_t *client)
{
char datebuf[128];
struct tm thetime;
time_t now;
time_t stayed;
const char *referrer, *user_agent, *username;
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
stayed = now - client->con->con_time;
if (client->username == NULL)
username = "-";
else
username = client->username;
referrer = httpp_getvar (client->parser, "referer");
if (referrer == NULL)
referrer = "-";
user_agent = httpp_getvar (client->parser, "user-agent");
if (user_agent == NULL)
user_agent = "-";
log_write_direct (accesslog,
"%s - %H [%s] \"%H %H %H/%H\" %d %llu \"% H\" \"% H\" %llu",
client->con->ip,
username,
datebuf,
httpp_getvar (client->parser, HTTPP_VAR_REQ_TYPE),
httpp_getvar (client->parser, HTTPP_VAR_URI),
httpp_getvar (client->parser, HTTPP_VAR_PROTOCOL),
httpp_getvar (client->parser, HTTPP_VAR_VERSION),
client->respcode,
(long long unsigned int)client->con->sent_bytes,
referrer,
user_agent,
(long long unsigned int)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(const char *mount, const 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|%ld|%s",
datebuf,
mount,
listeners,
metadata);
}
void logging_mark(const char *username, const char *role)
{
ICECAST_LOG_INFO("######## -- MARK -- (requested by %#H with role %#H) ########", username, role);
logging_playlist("/admin/", "-- MARK --", 0);
}
void log_parse_failure (void *ctx, const char *fmt, ...)
{
char line [200];
va_list ap;
char *eol;
va_start (ap, fmt);
vsnprintf (line, sizeof (line), fmt, ap);
eol = strrchr (line, '\n');
if (eol) *eol='\0';
va_end (ap);
log_write (errorlog, 2, (char*)ctx, "", "%s", line);
}
void restart_logging (ice_config_t *config)
{
if (strcmp (config->error_log, "-"))
{
char fn_error[FILENAME_MAX];
snprintf (fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->error_log);
log_set_filename (errorlog, fn_error);
log_set_level (errorlog, config->loglevel);
log_set_trigger (errorlog, config->logsize);
log_set_archive_timestamp(errorlog, config->logarchive);
log_reopen (errorlog);
}
if (strcmp (config->access_log, "-"))
{
char fn_error[FILENAME_MAX];
snprintf (fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->access_log);
log_set_filename (accesslog, fn_error);
log_set_trigger (accesslog, config->logsize);
log_set_archive_timestamp (accesslog, config->logarchive);
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_set_trigger (playlistlog, config->logsize);
log_set_archive_timestamp (playlistlog, config->logarchive);
log_reopen (playlistlog);
}
log_set_lines_kept(errorlog, config->error_log_lines_kept);
log_set_lines_kept(accesslog, config->access_log_lines_kept);
log_set_lines_kept(playlistlog, config->playlist_log_lines_kept);
}