ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/logger.C
Revision: 1.20
Committed: Mon Oct 12 14:00:57 2009 UTC (14 years, 7 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_82, rel-2_81
Changes since 1.19: +7 -6 lines
Log Message:
clarify license

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 * The authors can be reached via e-mail to <support@deliantra.net>
23 */
24
25 #include <cstdarg>
26 #include <cstring>
27
28 #include <vector>
29
30 #include <sys/uio.h>
31 #include <pthread.h>
32
33 #include "global.h"
34 #include "dynbuf.h"
35 #include "util.h"
36
37 struct logline
38 {
39 struct timeval tv;
40 char *buf; // includes PREFIX_LEN garbage bytes
41 int len;
42 int flags;
43 };
44
45 static SMUTEX(mutex);
46 static SCOND(cond);
47 static int logfd = STDERR_FILENO;
48 static int logsync = 1;
49 static std::vector<logline, slice_allocator<logline> > queue;
50
51 void set_logfd (int fd)
52 {
53 SMUTEX_LOCK (mutex);
54 logfd = fd < 0 ? STDERR_FILENO : fd;
55 SMUTEX_UNLOCK (mutex);
56 }
57
58 #define PREFIX_LEN sizeof ("0000-00-00 00:00:00.0000+") - 1
59
60 static void
61 log_sync (logline &line)
62 {
63 struct tm lt;
64 char pfx [PREFIX_LEN];
65
66 localtime_r (&line.tv.tv_sec, &lt);
67
68 sprintf (pfx, "%04d-%02d-%02d %02d:%02d:%02d.%04d",
69 lt.tm_year + 1900,
70 lt.tm_mon + 1,
71 lt.tm_mday,
72 lt.tm_hour,
73 lt.tm_min,
74 lt.tm_sec,
75 (int)(line.tv.tv_usec / 100)
76 );
77
78 pfx [PREFIX_LEN - 1] = line.flags & logSync ? '=' : ' ';
79
80 struct iovec iov [2];
81
82 iov [0].iov_base = pfx;
83 iov [0].iov_len = PREFIX_LEN;
84
85 char *buf = line.buf;
86
87 while (char *end = strchr (buf, '\n'))
88 {
89 iov [1].iov_base = buf;
90 iov [1].iov_len = end - buf + 1;
91
92 writev (STDERR_FILENO, iov, 2);
93 if (logfd != STDERR_FILENO)
94 writev (logfd, iov, 2);
95
96 buf = end + 1;
97
98 if (buf == line.buf + line.len)
99 break;
100
101 pfx [PREFIX_LEN - 1] = '+';
102 }
103
104 sfree (line.buf, line.len);
105 }
106
107 static void *
108 logthread_proc (void *arg)
109 {
110 int idx = 0;
111
112 for (;;)
113 {
114 logline line;
115
116 SMUTEX_LOCK (mutex);
117
118 while (queue.empty ())
119 SCOND_WAIT (cond, mutex);
120
121 line = queue [idx++];
122
123 // this algorithm could result in an ever-increasing vector
124 // size if we log faster than we can write, but if that happens
125 // we have bigger problems.
126 if (idx == queue.size ())
127 {
128 queue.clear ();
129 idx = 0;
130 }
131
132 SMUTEX_UNLOCK (mutex);
133
134 log_sync (line);
135 }
136 }
137
138 void
139 log_cleanup ()
140 {
141 logsync = 1;
142
143 for (;;)
144 {
145 int done;
146
147 SMUTEX_LOCK (mutex);
148 done = queue.empty ();
149 SMUTEX_UNLOCK (mutex);
150
151 if (done)
152 break;
153
154 usleep (10000);
155 }
156 }
157
158 static void
159 af_child ()
160 {
161 logsync = 1;
162 }
163
164 static struct logthread : thread
165 {
166 logthread ()
167 {
168 pthread_atfork (0, 0, af_child);
169 start (logthread_proc);
170 logsync = 0;
171 }
172 } logthread;
173
174 void
175 LOG (int flags, const char *format, ...)
176 {
177 int level = flags & 15;
178
179 if (level > settings.debug)
180 return;
181
182 logline line;
183 gettimeofday (&line.tv, 0);
184
185 static dynbuf_text buf;
186
187 va_list ap;
188 va_start (ap, format);
189 buf.vprintf (format, ap);
190 va_end (ap);
191
192 buf << '\n';
193
194 line.buf = buf.linearise ();
195 line.len = buf.size ();
196
197 if (line.buf [line.len - 2] == '\n')
198 --line.len;
199
200 line.buf = salloc<char> (line.len, line.buf);
201
202 buf.clear ();
203
204 if (logsync)
205 flags |= logSync;
206
207 if (flags & logBacktrace)
208 {
209 line.buf [line.len - 1] = 0;
210 log_backtrace (line.buf);
211 line.buf [line.len - 1] = '\n';
212 }
213
214 line.flags = flags;
215
216 if (line.flags & logSync)
217 log_sync (line);
218 else
219 {
220 SMUTEX_LOCK (mutex);
221 queue.push_back (line);
222 SMUTEX_UNLOCK (mutex);
223 SCOND_SIGNAL (cond);
224 }
225 }
226