2 * UCW Library -- Logging to Files
4 * (c) 1997--2009 Martin Mares <mj@ucw.cz>
5 * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
14 #include "ucw/threads.h"
23 * Use of the private fields of struct log_stream:
25 * idata file descriptor
26 * udata various flags (FF_xxx)
27 * pdata original name with strftime escapes
28 * name current name of the log file
29 * (a dynamically allocated buffer)
33 FF_FORMAT_NAME = 1, // Name contains strftime escapes
34 FF_CLOSE_FD = 2, // Close the fd with the stream
37 #define MAX_EXPAND 64 // Maximum size of expansion of strftime escapes
39 static int log_switch_nest;
42 do_log_reopen(struct log_stream *ls, const char *name)
44 int fd = ucw_open(name, O_WRONLY | O_CREAT | O_APPEND, 0666);
46 die("Unable to open log file %s: %m", name);
57 ls->name = NULL; // We have to keep this consistent, die() below can invoke logging
59 ls->name = xstrdup(name);
63 do_log_switch(struct log_stream *ls, struct tm *tm)
65 if (!(ls->udata & FF_FORMAT_NAME))
71 do_log_reopen(ls, ls->pdata);
76 int buflen = strlen(ls->pdata) + MAX_EXPAND;
81 if (!log_switch_nest) // Avoid infinite loops if we die when switching logs
84 int l = strftime(name, buflen, ls->pdata, tm);
85 if (l < 0 || l >= buflen)
86 die("Error formatting log file name: %m");
87 if (!ls->name || strcmp(name, ls->name))
89 do_log_reopen(ls, name);
99 log_file(const char *name)
111 time_t tim = time(NULL);
112 return do_log_switch(localtime(&tim));
119 log_switch_disable(void)
125 log_switch_enable(void)
127 ASSERT(log_switch_nest);
131 /* destructor for standard files */
133 file_close(struct log_stream *ls)
135 if ((ls->udata & FF_CLOSE_FD) && ls->idata >= 0)
140 /* handler for standard files */
142 file_handler(struct log_stream *ls, const char *m, uns cat UNUSED)
144 if (ls->udata & FF_FORMAT_NAME)
146 // FIXME: pass the time
147 time_t now = time(NULL);
148 struct tm *tm = localtime(&now);
149 do_log_switch(ls, tm);
153 int r = write(ls->idata, m, len);
154 /* FIXME: check for errors here? */
158 /* assign log to a file descriptor */
159 /* initialize with the default formatting, does NOT close the descriptor */
163 struct log_stream *ls = log_new_stream();
165 ls->msgfmt = LSFMT_DEFAULT;
166 ls->handler = file_handler;
167 ls->close = file_close;
168 ls->name = xmalloc(16);
169 snprintf(ls->name, 16, "fd%d", fd);
173 /* open() a file (append mode) */
174 /* initialize with the default formatting */
176 log_new_file(const char *path)
178 struct log_stream *ls = log_new_stream();
180 ls->pdata = (void *) path;
181 if (strchr(path, '%'))
182 ls->udata = FF_FORMAT_NAME;
183 ls->udata |= FF_CLOSE_FD;
184 ls->msgfmt = LSFMT_DEFAULT;
185 ls->handler = file_handler;
186 ls->close = file_close;
188 time_t now = time(NULL);
189 struct tm *tm = localtime(&now);
190 do_log_switch(ls, tm); // die()'s on errors
196 int main(int argc, char **argv)
199 // log_file("/proc/self/fd/1");
200 // struct log_stream *ls = log_new_fd(1);
201 struct log_stream *ls = log_new_file("/tmp/quork-%Y%m%d-%H%M%S");
202 for (int i=1; i<argc; i++)
203 msg(L_INFO | ls->regnum, argv[i]);