WvStreams
wvlogfile.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * A "Log Receiver" that logs messages to a file
6 */
7#include "wvlogfile.h"
8#include "wvtimeutils.h"
9#include "wvdiriter.h"
10#include "strutils.h"
11#include "wvdailyevent.h"
12#include "wvfork.h"
13#include <time.h>
14#include <sys/types.h>
15#ifndef _WIN32
16#include <sys/wait.h>
17#endif
18
19#define MAX_LOGFILE_SZ 1024*1024*100 // 100 Megs
20
21#ifdef MACOS
22#define O_LARGEFILE 00000000 // MAC doesn't need Largefile support, so just make it a dummy value when ORd
23#endif
24
25static time_t gmtoffset()
26{
27 time_t nowgmt = time(NULL);
28 struct tm gmt = *gmtime(&nowgmt);
29 struct tm local = *localtime(&nowgmt);
30 time_t nowantilocal = mktime(&gmt); // mktime assumes gmt
31 return nowgmt - nowantilocal;
32}
33
34
35//----------------------------------- WvLogFileBase ------------------
36
37WvLogFileBase::WvLogFileBase(WvStringParm _filename, WvLog::LogLevel _max_level)
38 : WvLogRcv(_max_level),
39 WvFile(_filename, O_WRONLY|O_APPEND|O_CREAT|O_LARGEFILE, 0644)
40{
41 fsync_every = fsync_count = 0;
42}
43
44
45WvLogFileBase::WvLogFileBase(WvLog::LogLevel _max_level)
46 : WvLogRcv(_max_level)
47{
48 fsync_every = fsync_count = 0;
49}
50
51
52void WvLogFileBase::_mid_line(const char *str, size_t len)
53{
54 WvFile::write(str, len);
55}
56
57
59{
60 if (fsync_every)
61 {
62 fsync_count--;
63 if (fsync_count <= 0 || fsync_count > fsync_every)
64 {
65 fsync_count = fsync_every;
66 //WvFile::print("tick!\n");
67 WvFile::flush(1000);
68 fsync(getwfd());
69 }
70 }
71}
72
73#ifdef _WIN32
74#define TIME_FORMAT "%b %d %H:%M:%S" // timezones in win32 look stupid
75#else
76#define TIME_FORMAT "%b %d %H:%M:%S %Z"
77#endif
78
79void WvLogFileBase::_make_prefix(time_t timenow)
80{
81 struct tm* tmstamp = localtime(&timenow);
82 char timestr[30];
83 strftime(&timestr[0], 30, TIME_FORMAT, tmstamp);
84
85 prefix = WvString("%s: %s<%s>: ", timestr, last_source,
86 loglevels[last_level]);
87 prelen = prefix.len();
88}
89
90//----------------------------------- WvLogFile ----------------------
91
92WvLogFile::WvLogFile(WvStringParm _filename, WvLog::LogLevel _max_level,
93 int _keep_for, bool _force_new_line, bool _allow_append)
94 : WvLogFileBase(_max_level), keep_for(_keep_for), filename(_filename),
95 allow_append(_allow_append)
96{
97 WvLogRcv::force_new_line = _force_new_line;
98 // start_log(); // don't open log until the first message gets printed
99}
100
101void WvLogFile::_make_prefix(time_t timenow)
102{
103 if (!WvFile::isok())
104 start_log();
105
106 // struct tm *tmstamp = localtime(&timenow);
107 struct stat statbuf;
108
109 // Get the filesize
110 if (fstat(getfd(), &statbuf) == -1)
111 statbuf.st_size = 0;
112
113 // Make sure we are calculating last_day in the current time zone.
114 if (last_day != ((timenow + gmtoffset())/86400)
115 || statbuf.st_size > MAX_LOGFILE_SZ)
116 start_log();
117
119}
120
121static void trim_old_logs(WvStringParm filename, WvStringParm base,
122 int keep_for)
123{
124 if (!keep_for) return;
125 WvDirIter i(getdirname(filename), false);
126 for (i.rewind(); i.next(); )
127 {
128 // if it begins with the base name
129 if (!strncmp(i.ptr()->name, base, strlen(base)))
130 {
131 // and it's older than 'keep_for' days
132 if (i.ptr()->st_mtime < wvtime().tv_sec - keep_for*86400)
133 ::unlink(i.ptr()->fullname);
134 }
135 }
136}
137
138
139WvString WvLogFile::start_log()
140{
142
143 int num = 0;
144 struct stat statbuf;
145 time_t timenow = wvtime().tv_sec;
146 last_day = (timenow + gmtoffset()) / 86400;
147 struct tm* tmstamp = localtime(&timenow);
148 char buf[20];
149 WvString fullname;
150 strftime(buf, 20, "%Y-%m-%d", tmstamp);
151
152 // Get the next filename
153 do
154 fullname = WvString("%s.%s.%s", filename, buf, num++);
155 while (stat(fullname, &statbuf) != -1
156 && (statbuf.st_size >= MAX_LOGFILE_SZ || !allow_append));
157
158 WvString curname("%s.current", filename);
159 WvString base = getfilename(filename);
160
161 WvFile::open(fullname, O_WRONLY|O_APPEND|O_CREAT|O_LARGEFILE, 0644);
162
163#ifndef _WIN32 // no symlinks in win32
164 // Don't delete the file, unless it's a symlink!
165 int sym = readlink(curname, buf, 20);
166 if (sym > 0 || errno == ENOENT)
167 {
168 unlink(curname);
169 symlink(getfilename(fullname), curname);
170 }
171#endif
172
173#ifndef _WIN32
174 // We fork here because this can be really slow when the directory has
175 // (oh, say 32,000 files)
176 pid_t forky = wvfork();
177 if (!forky)
178 {
179 // ForkTwiceSoTheStupidThingWorksRight
180 if (!wvfork())
181 {
182 // Child will Look for old logs and purge them
183 trim_old_logs(filename, base, keep_for);
184 _exit(0);
185 }
186 _exit(0);
187 }
188 // In case a signal is in the process of being delivered...
189 pid_t rv;
190 while ((rv = waitpid(forky, NULL, 0)) != forky)
191 if (rv == -1 && errno != EINTR)
192 break;
193#else
194 // just do it in the foreground on Windows
195 trim_old_logs(filename, base, keep_for);
196#endif
197
198 return fullname;
199}
virtual bool flush(time_t msec_timeout)=0
flush the output buffer, if we can do it without delaying more than msec_timeout milliseconds at a ti...
virtual bool isok() const =0
By default, returns true if geterr() == 0.
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition wvstring.h:94
int getfd() const
Returns the Unix file descriptor for reading and writing.
Definition wvfdstream.h:81
int getwfd() const
Returns the Unix file descriptor for writing to this stream.
Definition wvfdstream.h:70
virtual void close()
Closes the file descriptors.
WvFile implements a stream connected to a file or Unix device.
Definition wvfile.h:29
Basic WvLogRcv that logs to a file.
Definition wvlogfile.h:17
virtual void _make_prefix(time_t now_sec)
Set the Prefix and Prefix Length (size_t prelen)
Definition wvlogfile.cc:79
virtual void _mid_line(const char *str, size_t len)
add text to the current log line.
Definition wvlogfile.cc:52
virtual void _end_line()
End this (Guaranteed NonEmpty) log line.
Definition wvlogfile.cc:58
WvLogRcv adds some intelligence to WvLogRcvBase, to keep track of line-prefix-printing and other form...
Definition wvlogrcv.h:29
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
Definition wvstream.cc:532
WvString is an implementation of a simple and efficient printable-string class.
Definition wvstring.h:330
Provides support for forking processes.
pid_t wvfork(int dontclose1=-1, int dontclose2=-1)
wvfork() just runs fork(), but it closes all file descriptors that are flagged close-on-exec,...
Definition wvfork.cc:71
WvString getfilename(WvStringParm fullname)
Take a full path/file name and splits it up into respective pathname and filename.
Definition strutils.cc:506