Load plugin trace message before load
[MonkeyD.git] / src / logfile.c
blobf3af70cd291765fb9a51eb0e218bc098d1599e09
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2010, Eduardo Silva P. <edsiper@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * Youu should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #define _GNU_SOURCE
23 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <arpa/inet.h>
27 #include <netinet/in.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <time.h>
31 #include <unistd.h>
32 #include <sys/uio.h>
33 #include <sys/ioctl.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/times.h>
39 #include "monkey.h"
40 #include "http.h"
41 #include "http_status.h"
42 #include "logfile.h"
43 #include "memory.h"
44 #include "config.h"
45 #include "user.h"
46 #include "utils.h"
47 #include "epoll.h"
48 #include "iov.h"
49 #include "clock.h"
50 #include "http.h"
51 #include "cache.h"
53 #include <sys/sysinfo.h>
55 void mk_logger_target_add(int fd, char *target)
57 struct log_target *new, *aux;
59 new = mk_mem_malloc(sizeof(struct log_target));
60 new->fd = fd;
61 new->target = target;
62 new->next = NULL;
64 if (!lt) {
65 lt = new;
66 return;
69 aux = lt;
70 while (aux->next)
71 aux = aux->next;
73 aux->next = new;
76 struct log_target *mk_logger_match(int fd)
78 struct log_target *aux;
80 aux = lt;
82 while (aux) {
83 if (aux->fd == fd) {
84 return aux;
86 aux = aux->next;
89 return NULL;
93 void *mk_logger_worker_init(void *args)
95 int efd, max_events = config->nhosts;
96 int i, bytes, err;
97 struct log_target *target = 0;
98 struct host *h = 0;
99 int flog;
100 long slen;
101 int timeout;
102 int clk;
104 /* pipe_size:
105 * ----------
106 * Linux set a pipe size usingto the PAGE_SIZE,
107 * check linux/include/pipe_fs_i.h for details:
109 * #define PIPE_SIZE PAGE_SIZE
111 * In the same header file we can found that every
112 * pipe has 16 pages, so our real memory allocation
113 * is: (PAGE_SIZE*PIPE_BUFFERS)
115 long pipe_size;
117 /* buffer_limit:
118 * -------------
119 * it means the maximum data that a monkey log pipe can contain.
121 long buffer_limit;
123 /* Monkey allow just 75% of a pipe capacity */
124 pipe_size = sysconf(_SC_PAGESIZE) * 16;
125 buffer_limit = (pipe_size * MK_LOGFILE_PIPE_LIMIT);
127 /* Creating poll */
128 efd = mk_epoll_create(max_events);
130 h = config->hosts;
131 while (h) {
132 /* Add access log file */
133 if( h->log_access[0] > 0 ) {
134 mk_epoll_add(efd, h->log_access[0],
135 MK_EPOLL_READ, MK_EPOLL_BEHAVIOR_DEFAULT);
136 mk_logger_target_add(h->log_access[0], h->access_log_path);
138 /* Add error log file */
139 if( h->log_error[0] > 0 ) {
140 mk_epoll_add(efd, h->log_error[0],
141 MK_EPOLL_READ, MK_EPOLL_BEHAVIOR_DEFAULT);
142 mk_logger_target_add(h->log_error[0], h->error_log_path);
144 h = h->next;
147 timeout = time(NULL) + MK_LOGFILE_TIMEOUT;
149 /* Reading pipe buffer */
150 while (1) {
151 usleep(1200);
153 struct epoll_event events[max_events];
154 int num_fds = epoll_wait(efd, events, max_events, -1);
156 clk = log_current_utime;
157 if (!h) {
158 h = config->hosts;
161 for (i = 0; i < num_fds; i++) {
162 target = mk_logger_match(events[i].data.fd);
164 if (!target) {
165 printf("\nERROR matching host/epoll_fd");
166 fflush(stdout);
167 continue;
170 err = ioctl(target->fd, FIONREAD, &bytes);
171 if (err == -1) {
172 perror("ioctl");
175 if (bytes < buffer_limit && clk <= timeout) {
176 break;
178 else {
179 timeout = clk + MK_LOGFILE_TIMEOUT;
180 flog = open(target->target, O_WRONLY | O_CREAT, 0644);
182 if (flog == -1) {
183 printf("\n* error: check your logfile file permission");
184 perror("open");
185 continue;
188 lseek(flog, 0, SEEK_END);
189 slen = splice(events[i].data.fd, NULL, flog,
190 NULL, bytes, SPLICE_F_MOVE);
191 if (slen == -1) {
192 perror("splice");
194 close(flog);
200 struct mk_iov *mk_logger_iov_get()
202 return pthread_getspecific(mk_cache_iov_log);
205 void mk_logger_iov_free(struct mk_iov *iov)
207 mk_iov_free_marked(iov);
210 /* Log access and error messages */
211 int mk_logger_write_log(struct client_request *cr, struct log_info *log,
212 struct host *h)
214 struct mk_iov *iov;
215 mk_pointer *status, method, protocol;
216 struct sched_list_node *sched;
217 struct sched_connection *conx;
219 #ifdef TRACE
220 MK_TRACE("Logger, Writting to log file [FD %i]", cr->socket);
221 #endif
223 if (log->status != S_LOG_ON) {
224 return 0;
227 iov = mk_logger_iov_get();
229 sched = mk_sched_get_thread_conf();
230 conx = mk_sched_get_connection(sched, cr->socket);
232 /* client IP address */
233 mk_iov_add_entry(iov, conx->ipv4.data, conx->ipv4.len,
234 mk_logfile_iov_dash, MK_IOV_NOT_FREE_BUF);
236 /* Date/time when object was requested */
237 mk_iov_add_entry(iov, log_current_time.data, log_current_time.len,
238 mk_iov_space, MK_IOV_NOT_FREE_BUF);
240 /* Register a successfull request */
241 if (log->final_response == M_HTTP_OK ||
242 log->final_response == M_REDIR_MOVED ||
243 log->final_response == M_REDIR_MOVED_T ||
244 log->final_response == M_NOT_MODIFIED ||
245 log->final_response == M_HTTP_PARTIAL) {
247 /* HTTP method required */
248 method = mk_http_method_check_str(log->method);
249 mk_iov_add_entry(iov, method.data, method.len, mk_iov_space,
250 MK_IOV_NOT_FREE_BUF);
252 /* HTTP URI required */
253 mk_iov_add_entry(iov, log->uri.data, log->uri.len,
254 mk_iov_space, MK_IOV_NOT_FREE_BUF);
257 if (log->protocol) {
258 protocol = mk_http_protocol_check_str(log->protocol);
259 mk_iov_add_entry(iov, protocol.data, protocol.len,
260 mk_iov_space, MK_IOV_NOT_FREE_BUF);
263 /* HTTP status code */
264 status = (mk_pointer *)
265 mk_http_status_get(log->final_response);
266 mk_iov_add_entry(iov, status->data, status->len,
267 mk_iov_space, MK_IOV_NOT_FREE_BUF);
269 /* object size */
270 if (log->size_p.data) {
271 mk_iov_add_entry(iov,
272 log->size_p.data,
273 log->size_p.len, mk_iov_none, MK_IOV_NOT_FREE_BUF);
275 else {
276 mk_iov_add_entry(iov,
277 "0\r\n", 3, mk_iov_none, MK_IOV_NOT_FREE_BUF);
279 /* Send info to pipe */
280 mk_iov_send(h->log_access[1], iov, MK_IOV_SEND_TO_PIPE);
282 else { /* Register some error */
283 mk_iov_add_entry(iov,
284 log->error_msg.data,
285 log->error_msg.len, mk_iov_space, MK_IOV_NOT_FREE_BUF);
287 /* Check for error extra details */
288 if (log->error_details.data) {
289 mk_iov_add_entry(iov,
290 log->error_details.data,
291 log->error_details.len,
292 mk_iov_lf,
293 MK_IOV_NOT_FREE_BUF);
295 else{
296 mk_iov_add_entry(iov, mk_iov_lf.data,
297 mk_iov_lf.len, mk_iov_none, MK_IOV_NOT_FREE_BUF);
300 mk_iov_send(h->log_error[1], iov, MK_IOV_SEND_TO_PIPE);
302 mk_logger_iov_free(iov);
303 return 0;
306 /* Write Monkey's PID */
307 int mk_logger_register_pid()
309 FILE *pid_file;
311 remove(config->pid_file_path);
312 config->pid_status = VAR_OFF;
313 if ((pid_file = fopen(config->pid_file_path, "w")) == NULL) {
314 puts("Error: I can't log pid of monkey");
315 exit(1);
317 fprintf(pid_file, "%i", getpid());
318 fclose(pid_file);
319 config->pid_status = VAR_ON;
321 return 0;
324 /* Remove PID file */
325 int mk_logger_remove_pid()
327 mk_user_undo_uidgid();
328 return remove(config->pid_file_path);