logging.c 6.86 KB
Newer Older
1 2 3 4 5
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
6
 * Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
7 8 9 10
 *                      Michael Smith <msmith@xiph.org>,
 *                      oddsock <oddsock@xiph.org>,
 *                      Karl Heyes <karl@xiph.org>
 *                      and others (see AUTHORS for details).
11
 * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
12 13
 */

14 15 16 17
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Jack Moffitt's avatar
Jack Moffitt committed
18 19
#include <stdio.h>
#include <time.h>
20
#include <string.h>
Jack Moffitt's avatar
Jack Moffitt committed
21

22 23
#include "common/thread/thread.h"
#include "common/httpp/httpp.h"
Jack Moffitt's avatar
Jack Moffitt committed
24

25
#include "logging.h"
Jack Moffitt's avatar
Jack Moffitt committed
26 27 28 29
#include "connection.h"
#include "refbuf.h"
#include "client.h"

30
#include "compat.h"
31
#include "cfgfile.h"
32
#include "util.h"
Jack Moffitt's avatar
Jack Moffitt committed
33

34 35
#ifdef _WIN32
#define snprintf _snprintf
36
#define vsnprintf _vsnprintf
37 38
#endif

Jack Moffitt's avatar
Jack Moffitt committed
39
/* the global log descriptors */
40 41
int errorlog = 0;
int accesslog = 0;
42
int playlistlog = 0;
43 44 45

#ifdef _WIN32
/* Since strftime's %z option on win32 is different, we need
46
 to go through a few loops to get the same info as %z */
47 48
int get_clf_time (char *buffer, unsigned len, struct tm *t)
{
49
    char sign;
50
    char timezone_string[7];
51 52 53 54 55 56 57
    struct tm gmt;
    time_t time1 = time(NULL);
    int time_days, time_hours, time_tz;
    int tempnum1, tempnum2;
    struct tm *thetime;
    time_t now;

58 59 60 61 62 63 64 65 66
#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 */
67

68 69 70 71 72
    if (!thetime) {
        snprintf(buffer, len, "<<BAD TIMESTAMP>>");
        return 0;
    }

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    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 = '+';
    }
98

99
    snprintf(timezone_string, sizeof(timezone_string), " %c%.2d%.2d", sign, time_tz / 60, time_tz % 60);
100 101 102 103

    now = time(NULL);

    thetime = localtime(&now);
104
    strftime(buffer, len - sizeof(timezone_string), "%d/%b/%Y:%H:%M:%S", thetime);
105 106 107
    strcat(buffer, timezone_string);
    return 1;
}
108
#endif
109
/*
110 111 112 113 114 115 116 117 118 119 120 121 122
 ** 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
 */
Jack Moffitt's avatar
Jack Moffitt committed
123 124
void logging_access(client_t *client)
{
125
    char datebuf[128];
126
    struct tm thetime;
127 128
    time_t now;
    time_t stayed;
129
    const char *referrer, *user_agent, *username;
130 131 132

    now = time(NULL);

133
    localtime_r (&now, &thetime);
134
    /* build the data */
135
#ifdef _WIN32
136 137
    memset(datebuf, '\000', sizeof(datebuf));
    get_clf_time(datebuf, sizeof(datebuf)-1, &thetime);
138
#else
139
    strftime (datebuf, sizeof(datebuf), LOGGING_FORMAT_CLF, &thetime);
140
#endif
141 142 143

    stayed = now - client->con->con_time;

144
    if (client->username == NULL)
145
        username = "-";
146 147 148
    else
        username = client->username;

149 150 151 152 153 154 155 156
    referrer = httpp_getvar (client->parser, "referer");
    if (referrer == NULL)
        referrer = "-";

    user_agent = httpp_getvar (client->parser, "user-agent");
    if (user_agent == NULL)
        user_agent = "-";

157
    log_write_direct (accesslog,
158
            "%s - %H [%s] \"%H %H %H/%H\" %d %llu \"% H\" \"% H\" %llu",
159
            client->con->ip,
160
            username,
161
            datebuf,
162 163 164 165
            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),
166
            client->respcode,
167
            (long long unsigned int)client->con->sent_bytes,
168 169
            referrer,
            user_agent,
170
            (long long unsigned int)stayed);
Jack Moffitt's avatar
Jack Moffitt committed
171
}
172 173 174
/* 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 */
175
void logging_playlist(const char *mount, const char *metadata, long listeners)
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
{
    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 */
197
    log_write_direct (playlistlog, "%s|%s|%ld|%s",
198 199 200 201 202
             datebuf,
             mount,
             listeners,
             metadata);
}
Jack Moffitt's avatar
Jack Moffitt committed
203 204


205 206 207 208 209 210 211 212 213 214 215 216 217 218
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);
}

Jack Moffitt's avatar
Jack Moffitt committed
219

220
void restart_logging (ice_config_t *config)
221 222 223 224 225 226 227
{
    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);
228 229
        log_set_trigger (errorlog, config->logsize);
        log_set_archive_timestamp(errorlog, config->logarchive);
230 231 232 233 234 235 236 237
        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);
238 239
        log_set_trigger (accesslog, config->logsize);
        log_set_archive_timestamp (accesslog, config->logarchive);
240 241
        log_reopen (accesslog);
    }
242 243 244 245 246 247

    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);
248 249
        log_set_trigger (playlistlog, config->logsize);
        log_set_archive_timestamp (playlistlog, config->logarchive);
250 251
        log_reopen (playlistlog);
    }
252
}