ModDaemon.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 50 Log file handling */
10 
11 #include "squid.h"
12 #include "cbdata.h"
13 #include "comm/Loops.h"
14 #include "fatal.h"
15 #include "fde.h"
16 #include "globals.h"
17 #include "log/Config.h"
18 #include "log/File.h"
19 #include "log/ModDaemon.h"
20 #include "SquidConfig.h"
21 #include "SquidIpc.h"
22 #include "SquidTime.h"
23 
24 #include <cerrno>
25 
26 /* How many buffers to keep before we say we've buffered too much */
27 #define LOGFILE_MAXBUFS 128
28 
29 /* Size of the logfile buffer */
30 /*
31  * For optimal performance this should match LOGFILE_BUFSIZ in logfile-daemon.c
32  */
33 #define LOGFILE_BUFSZ 32768
34 
35 /* How many seconds between warnings */
36 #define LOGFILE_WARN_TIME 30
37 
44 
45 static void logfile_mod_daemon_append(Logfile * lf, const char *buf, int len);
46 
47 struct _l_daemon {
48  int rfd, wfd;
49  char eol;
50  pid_t pid;
53  int nbufs;
55 };
56 
57 typedef struct _l_daemon l_daemon_t;
58 
59 /* Internal code */
60 static void
62 {
63  l_daemon_t *ll = (l_daemon_t *) lf->data;
65 
66  debugs(50, 5, "logfileNewBuffer: " << lf->path << ": new buffer");
67 
68  b = static_cast<logfile_buffer_t*>(xcalloc(1, sizeof(logfile_buffer_t)));
69  assert(b != NULL);
70  b->buf = static_cast<char*>(xcalloc(1, LOGFILE_BUFSZ));
71  assert(b->buf != NULL);
72  b->size = LOGFILE_BUFSZ;
73  b->written_len = 0;
74  b->len = 0;
75  dlinkAddTail(b, &b->node, &ll->bufs);
76  ++ ll->nbufs;
77 }
78 
79 static void
81 {
82  l_daemon_t *ll = (l_daemon_t *) lf->data;
83  assert(b != NULL);
84  dlinkDelete(&b->node, &ll->bufs);
85  -- ll->nbufs;
86  xfree(b->buf);
87  xfree(b);
88 }
89 
90 static void
91 logfileHandleWrite(int, void *data)
92 {
93  Logfile *lf = static_cast<Logfile *>(data);
94  l_daemon_t *ll = static_cast<l_daemon_t *>(lf->data);
95 
96  /*
97  * We'll try writing the first entry until its done - if we
98  * get a partial write then we'll re-schedule until its completed.
99  * Its naive but it'll do for now.
100  */
101  if (!ll->bufs.head) // abort if there is nothing pending right now.
102  return;
103 
104  logfile_buffer_t *b = static_cast<logfile_buffer_t*>(ll->bufs.head->data);
105  assert(b != NULL);
106  ll->flush_pending = 0;
107 
108  int ret = FD_WRITE_METHOD(ll->wfd, b->buf + b->written_len, b->len - b->written_len);
109  int xerrno = errno;
110  debugs(50, 3, lf->path << ": write returned " << ret);
111  if (ret < 0) {
112  if (ignoreErrno(xerrno)) {
113  /* something temporary */
115  ll->flush_pending = 1;
116  return;
117  }
118  debugs(50, DBG_IMPORTANT,"logfileHandleWrite: " << lf->path << ": error writing (" << xstrerr(xerrno) << ")");
119  /* XXX should handle this better */
120  fatal("I don't handle this error well!");
121  }
122  if (ret == 0) {
123  /* error? */
124  debugs(50, DBG_IMPORTANT, "logfileHandleWrite: " << lf->path << ": wrote 0 bytes?");
125  /* XXX should handle this better */
126  fatal("I don't handle this error well!");
127  }
128  /* ret > 0, so something was written */
129  b->written_len += ret;
130  assert(b->written_len <= b->len);
131  if (b->written_len == b->len) {
132  /* written the whole buffer! */
133  logfileFreeBuffer(lf, b);
134  b = NULL;
135  }
136  /* Is there more to write? */
137  if (!ll->bufs.head)
138  return;
139  /* there is, so schedule more */
140 
142  ll->flush_pending = 1;
143  return;
144 }
145 
146 static void
148 {
149  l_daemon_t *ll = (l_daemon_t *) lf->data;
150  if (ll->flush_pending || ll->bufs.head == NULL) {
151  return;
152  }
153  ll->flush_pending = 1;
154  if (ll->bufs.head) {
155  logfile_buffer_t *b = static_cast<logfile_buffer_t*>(ll->bufs.head->data);
156  if (b->len + 2 <= b->size)
157  logfile_mod_daemon_append(lf, "F\n", 2);
158  }
159  /* Ok, schedule a write-event */
161 }
162 
163 static void
164 logfile_mod_daemon_append(Logfile * lf, const char *buf, int len)
165 {
166  l_daemon_t *ll = (l_daemon_t *) lf->data;
167  logfile_buffer_t *b;
168  int s;
169 
170  /* Is there a buffer? If not, create one */
171  if (ll->bufs.head == NULL) {
172  logfileNewBuffer(lf);
173  }
174  debugs(50, 3, "logfile_mod_daemon_append: " << lf->path << ": appending " << len << " bytes");
175  /* Copy what can be copied */
176  while (len > 0) {
177  b = static_cast<logfile_buffer_t*>(ll->bufs.tail->data);
178  debugs(50, 3, "logfile_mod_daemon_append: current buffer has " << b->len << " of " << b->size << " bytes before append");
179  s = min(len, (b->size - b->len));
180  memcpy(b->buf + b->len, buf, s);
181  len = len - s;
182  buf = buf + s;
183  b->len = b->len + s;
184  assert(b->len <= LOGFILE_BUFSZ);
185  assert(len >= 0);
186  if (len > 0) {
187  logfileNewBuffer(lf);
188  }
189  }
190 }
191 
192 /*
193  * only schedule a flush (write) if one isn't scheduled.
194  */
195 static void
196 logfileFlushEvent(void *data)
197 {
198  Logfile *lf = static_cast<Logfile *>(data);
199 
200  /*
201  * This might work better if we keep track of when we wrote last and only
202  * schedule a write if we haven't done so in the last second or two.
203  */
204  logfileQueueWrite(lf);
205  eventAdd("logfileFlush", logfileFlushEvent, lf, 1.0, 1);
206 }
207 
208 /* External code */
209 
210 int
211 logfile_mod_daemon_open(Logfile * lf, const char *path, size_t, int)
212 {
213  const char *args[5];
214  char *tmpbuf;
215  l_daemon_t *ll;
216 
223 
224  cbdataInternalLock(lf); // WTF?
225  debugs(50, DBG_IMPORTANT, "Logfile Daemon: opening log " << path);
226  ll = static_cast<l_daemon_t*>(xcalloc(1, sizeof(*ll)));
227  lf->data = ll;
228  ll->eol = 1;
229  {
230  Ip::Address localhost;
231  args[0] = "(logfile-daemon)";
232  args[1] = path;
233  args[2] = NULL;
234  localhost.setLocalhost();
235  ll->pid = ipcCreate(IPC_STREAM, Log::TheConfig.logfile_daemon, args, "logfile-daemon", localhost, &ll->rfd, &ll->wfd, NULL);
236  if (ll->pid < 0)
237  fatal("Couldn't start logfile helper");
238  }
239  ll->nbufs = 0;
240 
241  /* Queue the initial control data */
242  tmpbuf = static_cast<char*>(xmalloc(BUFSIZ));
243  snprintf(tmpbuf, BUFSIZ, "r%d\nb%d\n", Config.Log.rotateNumber, Config.onoff.buffered_logs);
244  logfile_mod_daemon_append(lf, tmpbuf, strlen(tmpbuf));
245  xfree(tmpbuf);
246 
247  /* Start the flush event */
248  eventAdd("logfileFlush", logfileFlushEvent, lf, 1.0, 1);
249 
250  return 1;
251 }
252 
253 static void
255 {
256  l_daemon_t *ll = static_cast<l_daemon_t *>(lf->data);
257  debugs(50, DBG_IMPORTANT, "Logfile Daemon: closing log " << lf->path);
258  logfileFlush(lf);
259  if (ll->rfd == ll->wfd)
260  comm_close(ll->rfd);
261  else {
262  comm_close(ll->rfd);
263  comm_close(ll->wfd);
264  }
265  kill(ll->pid, SIGTERM);
267  xfree(ll);
268  lf->data = NULL;
269  cbdataInternalUnlock(lf); // WTF??
270 }
271 
272 static void
273 logfile_mod_daemon_rotate(Logfile * lf, const int16_t)
274 {
275  char tb[3];
276  debugs(50, DBG_IMPORTANT, "logfileRotate: " << lf->path);
277  tb[0] = 'R';
278  tb[1] = '\n';
279  tb[2] = '\0';
280  logfile_mod_daemon_append(lf, tb, 2);
281 }
282 
283 /*
284  * This routine assumes that up to one line is written. Don't try to
285  * call this routine with more than one line or subsequent lines
286  * won't be prefixed with the command type and confuse the logging
287  * daemon somewhat.
288  */
289 static void
290 logfile_mod_daemon_writeline(Logfile * lf, const char *buf, size_t len)
291 {
292  l_daemon_t *ll = static_cast<l_daemon_t *>(lf->data);
293  /* Make sure the logfile buffer isn't too large */
294  if (ll->nbufs > LOGFILE_MAXBUFS) {
297  debugs(50, DBG_IMPORTANT, "Logfile: " << lf->path << ": queue is too large; some log messages have been lost.");
298  }
299  return;
300  }
301 
302  /* Are we eol? If so, prefix with our logfile command byte */
303  if (ll->eol == 1) {
304  logfile_mod_daemon_append(lf, "L", 1);
305  ll->eol = 0;
306  }
307 
308  /* Append this data to the end buffer; create a new one if needed */
309  logfile_mod_daemon_append(lf, buf, len);
310 }
311 
312 static void
314 {
315  l_daemon_t *ll = static_cast<l_daemon_t *>(lf->data);
316  assert(ll->eol == 1);
317  // logfile_mod_daemon_writeline() sends the starting command
318 }
319 
320 static void
322 {
323  l_daemon_t *ll = static_cast<l_daemon_t *>(lf->data);
324  logfile_buffer_t *b;
325  if (ll->eol == 1) // logfile_mod_daemon_writeline() wrote nothing
326  return;
327  ll->eol = 1;
328  /* Kick a write off if the head buffer is -full- */
329  if (ll->bufs.head != NULL) {
330  b = static_cast<logfile_buffer_t*>(ll->bufs.head->data);
331  if (b->node.next != NULL || !Config.onoff.buffered_logs)
332  logfileQueueWrite(lf);
333  }
334 }
335 
336 static void
338 {
339  l_daemon_t *ll = static_cast<l_daemon_t *>(lf->data);
340  if (commUnsetNonBlocking(ll->wfd)) {
341  debugs(50, DBG_IMPORTANT, "Logfile Daemon: Couldn't set the pipe blocking for flush! You're now missing some log entries.");
342  return;
343  }
344  while (ll->bufs.head != NULL) {
345  logfileHandleWrite(ll->wfd, lf);
346  }
347  if (commSetNonBlocking(ll->wfd)) {
348  fatalf("Logfile Daemon: %s: Couldn't set the pipe non-blocking for flush!\n", lf->path);
349  return;
350  }
351 }
352 
void fatal(const char *message)
Definition: fatal.cc:28
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
#define BUFSIZ
Definition: defines.h:20
#define xmalloc
static void logfileNewBuffer(Logfile *lf)
Definition: ModDaemon.cc:61
void setLocalhost()
Definition: Address.cc:255
void eventDelete(EVH *func, void *arg)
Definition: event.cc:130
#define LOGFILE_WARN_TIME
Definition: ModDaemon.cc:36
pid_t pid
Definition: ModDaemon.cc:50
static LOGFLUSH logfile_mod_daemon_flush
Definition: ModDaemon.cc:42
static LOGLINESTART logfile_mod_daemon_linestart
Definition: ModDaemon.cc:39
char eol
Definition: ModDaemon.cc:49
void cbdataInternalLock(const void *p)
Definition: cbdata.cc:331
int written_len
Definition: File.h:25
#define LOGFILE_BUFSZ
Definition: ModDaemon.cc:33
LogConfig TheConfig
Definition: Config.cc:15
int commSetNonBlocking(int fd)
Definition: comm.cc:1037
static void logfileFlushEvent(void *data)
Definition: ModDaemon.cc:196
#define comm_close(x)
Definition: comm.h:27
static void logfileFreeBuffer(Logfile *lf, logfile_buffer_t *b)
Definition: ModDaemon.cc:80
int flush_pending
Definition: ModDaemon.cc:51
int rotateNumber
Definition: SquidConfig.h:189
static LOGWRITE logfile_mod_daemon_writeline
Definition: ModDaemon.cc:38
static void logfileQueueWrite(Logfile *lf)
Definition: ModDaemon.cc:147
LOGWRITE * f_linewrite
Definition: File.h:58
#define DBG_IMPORTANT
Definition: Debug.h:41
dlink_list bufs
Definition: ModDaemon.cc:52
void * data
Definition: File.h:55
void logfileFlush(Logfile *lf)
Definition: File.cc:139
int commUnsetNonBlocking(int fd)
Definition: comm.cc:1070
static LOGROTATE logfile_mod_daemon_rotate
Definition: ModDaemon.cc:41
#define NULL
Definition: types.h:166
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
int buffered_logs
Definition: SquidConfig.h:289
void LOGLINEEND(Logfile *)
Definition: File.h:33
void LOGROTATE(Logfile *, const int16_t)
Definition: File.h:35
LOGLINEEND * f_lineend
Definition: File.h:59
struct SquidConfig::@102 Log
int last_warned
Definition: ModDaemon.cc:54
#define assert(EX)
Definition: assert.h:19
char * buf
Definition: File.h:22
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
LOGCLOSE * f_close
Definition: File.h:62
void LOGWRITE(Logfile *, const char *, size_t len)
Definition: File.h:32
static LOGLINEEND logfile_mod_daemon_lineend
Definition: ModDaemon.cc:40
int FD_WRITE_METHOD(int fd, const char *buf, int len)
Definition: fde.h:200
static LOGCLOSE logfile_mod_daemon_close
Definition: ModDaemon.cc:43
pid_t ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc)
Definition: ipc.cc:62
LOGROTATE * f_rotate
Definition: File.h:61
time_t squid_curtime
Definition: stub_time.cc:17
#define xfree
Definition: File.h:39
void LOGLINESTART(Logfile *)
Definition: File.h:31
int logfile_mod_daemon_open(Logfile *lf, const char *path, size_t, int)
Definition: ModDaemon.cc:211
int ignoreErrno(int ierrno)
Definition: comm.cc:1411
dlink_node node
Definition: File.h:26
struct SquidConfig::@111 onoff
static void logfile_mod_daemon_append(Logfile *lf, const char *buf, int len)
Definition: ModDaemon.cc:164
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:224
LOGFLUSH * f_flush
Definition: File.h:60
static void logfileHandleWrite(int, void *data)
Definition: ModDaemon.cc:91
void LOGFLUSH(Logfile *)
Definition: File.h:34
#define LOGFILE_MAXBUFS
Definition: ModDaemon.cc:27
LOGLINESTART * f_linestart
Definition: File.h:57
int nbufs
Definition: ModDaemon.cc:53
static StatHist s
A const & min(A const &lhs, A const &rhs)
#define IPC_STREAM
Definition: defines.h:108
void cbdataInternalUnlock(const void *p)
Definition: cbdata.cc:357
char path[MAXPATHLEN]
Definition: File.h:46
#define COMM_SELECT_WRITE
Definition: defines.h:25
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:108
void LOGCLOSE(Logfile *)
Definition: File.h:36
class SquidConfig Config
Definition: SquidConfig.cc:12

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors