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-2018, 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

Marvin Scholz's avatar
Marvin Scholz committed
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 */
Michael Smith's avatar
Michael Smith committed
40 41
int errorlog = 0;
int accesslog = 0;
42
int playlistlog = 0;
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
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 */
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
47 48
int get_clf_time (char *buffer, unsigned len, struct tm *t)
{
49
    char sign;
50
    char timezone_string[7];
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
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 */
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
67

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

Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
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);
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
100 101 102 103

    now = time(NULL);

    thetime = localtime(&now);
104
    strftime(buffer, len - sizeof(timezone_string), "%d/%b/%Y:%H:%M:%S", thetime);
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
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 */
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
135
#ifdef _WIN32
136 137
    memset(datebuf, '\000', sizeof(datebuf));
    get_clf_time(datebuf, sizeof(datebuf)-1, &thetime);
Ed "oddsock" Zaleski's avatar
Ed "oddsock" Zaleski committed
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
}