aboutsummaryrefslogtreecommitdiffstats
path: root/vespalog/src/vespa/log/log-target-file.cpp
blob: ba60d58abacf9d9a5186b521f78a8e4de450f8d8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "log.h"
LOG_SETUP(".log");
#include "log-target-file.h"
#include "internal.h"

#include <unistd.h>
#include <cstring>
#include <fcntl.h>
#include <cerrno>
#include <cassert>

namespace ns_log {

#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif

LogTargetFile::LogTargetFile(const char *target)
    : LogTarget(target),
      _failstate(FS_OK)
{
    memset(_fname, 0, sizeof(_fname));
    const char *fname = target + strlen("file:");
    assert(strlen(fname) < sizeof(_fname));
    // NOTE: This function cannot LOG()
    if (strncmp(target, "file:", strlen("file:")) != 0) {
        throwInvalid("Illegal log target '%s'", target);
    }
    strcpy(_fname, fname);
    int fd = open(_fname, O_WRONLY | O_CREAT | O_APPEND | O_NOCTTY | O_LARGEFILE,
               0666);
    if (fd == -1) {
        throwInvalid("Cannot open log target file '%s': %s",
                     target + strlen("file:"), strerror(errno));
    }
    close(fd);
}

LogTargetFile::~LogTargetFile()
{
}

// Here we must support log rotation. We do this by reopening the filename.
int
LogTargetFile::write(const char *buf, int bufLen)
{
    int fd = open(_fname,
                  O_WRONLY | O_CREAT | O_APPEND | O_NOCTTY | O_LARGEFILE,
                  0666);
    if (fd < 0) {
        if (_failstate == FS_OK) {
            _failstate = FS_FAILED;
            LOG(warning, "cannot create %s: %s", _fname, strerror(errno));
            LOG(warning, "Log file failed, falling back to stderr logging");
        }
        fd = dup(STDERR_FILENO);
    } else {
        if (_failstate != FS_OK) {
            _failstate = FS_OK;
        }
    }
    int retVal = ::write(fd, buf, bufLen);
    close(fd);
    return retVal;
}

} // end namespace ns_log