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.
13 #include <ucw/log-internal.h>
15 #include <ucw/threads.h>
16 #include <ucw/simple-lists.h>
26 struct log_stream ls; // ls.name is the current name of the log file
29 char *orig_name; // Original name with strftime escapes
32 #define MAX_EXPAND 64 // Maximum size of expansion of strftime escapes
34 static int log_switch_nest;
37 do_log_reopen(struct file_stream *fs, const char *name)
39 int fd = ucw_open(name, O_WRONLY | O_CREAT | O_APPEND, 0666);
41 die("Unable to open log file %s: %m", name);
45 if (fs->flags & FF_FD2_FOLLOWS)
50 fs->ls.name = NULL; // We have to keep the stream consistent -- die() below can invoke logging
52 fs->ls.name = xstrdup(name);
56 do_log_switch(struct file_stream *fs, struct tm *tm)
58 if (!(fs->flags & FF_FORMAT_NAME))
64 do_log_reopen(fs, fs->orig_name);
69 int buflen = strlen(fs->orig_name) + MAX_EXPAND;
74 if (!log_switch_nest) // Avoid infinite loops if we die when switching logs
77 int l = strftime(name, buflen, fs->orig_name, tm);
78 if (l < 0 || l >= buflen)
79 die("Error formatting log file name: %m");
80 if (!fs->ls.name || strcmp(name, fs->ls.name))
82 do_log_reopen(fs, name);
92 file_close(struct log_stream *ls)
94 struct file_stream *fs = (struct file_stream *) ls;
95 if ((fs->flags & FF_CLOSE_FD) && fs->fd >= 0)
102 file_handler(struct log_stream *ls, struct log_msg *m)
104 struct file_stream *fs = (struct file_stream *) ls;
105 if ((fs->flags & FF_FORMAT_NAME) && m->tm)
106 do_log_switch(fs, m->tm);
108 int r = write(fs->fd, m->m, m->m_len);
109 return ((r < 0) ? errno : 0);
113 log_new_fd(int fd, uint flags)
115 struct log_stream *ls = log_new_stream(sizeof(struct file_stream));
116 struct file_stream *fs = (struct file_stream *) ls;
119 ls->msgfmt = LSFMT_DEFAULT;
120 ls->handler = file_handler;
121 ls->close = file_close;
122 ls->name = xmalloc(16);
123 snprintf(ls->name, 16, "fd%d", fd);
128 log_new_file(const char *path, uint flags)
130 struct log_stream *ls = log_new_stream(sizeof(struct file_stream));
131 struct file_stream *fs = (struct file_stream *) ls;
133 fs->flags = FF_CLOSE_FD | flags;
134 fs->orig_name = xstrdup(path);
135 if (strchr(path, '%'))
136 fs->flags |= FF_FORMAT_NAME;
137 ls->msgfmt = LSFMT_DEFAULT;
138 ls->handler = file_handler;
139 ls->close = file_close;
141 time_t now = time(NULL);
142 struct tm *tm = localtime(&now);
144 do_log_switch(fs, tm); // die()'s on errors
151 time_t now = time(NULL);
152 struct tm *tm = localtime(&now);
156 for (int i=0; i < log_streams_after; i++)
157 if (log_streams.ptr[i]->handler == file_handler)
158 switched |= do_log_switch((struct file_stream *) log_streams.ptr[i], tm);
163 log_switch_disable(void)
169 log_switch_enable(void)
171 ASSERT(log_switch_nest);
176 log_file(const char *name)
181 log_set_default_stream(log_new_file(name, FF_FD2_FOLLOWS));
186 int main(int argc, char **argv)
189 log_file("/proc/self/fd/1");
190 // struct log_stream *ls = log_new_fd(1, 0);
191 // struct log_stream *ls = log_new_file("/tmp/quork-%Y%m%d-%H%M%S", 0);
192 for (int i=1; i<argc; i++)
193 msg(L_INFO, argv[i]);