Logger: move specific values to header
[MonkeyD.git] / src / logfile.c
blob795f91490bb131b60ec857493868842ae7c3b65c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /* Monkey HTTP Daemon
4 * ------------------
5 * Copyright (C) 2001-2008, Eduardo Silva P.
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_client(efd, h->log_access[0], MK_EPOLL_BEHAVIOR_DEFAULT);
135 mk_logger_target_add(h->log_access[0], h->access_log_path);
137 /* Add error log file */
138 if( h->log_error[0] > 0 ) {
139 mk_epoll_add_client(efd, h->log_error[0], MK_EPOLL_BEHAVIOR_DEFAULT);
140 mk_logger_target_add(h->log_error[0], h->error_log_path);
142 h = h->next;
145 timeout = time(NULL) + MK_LOGFILE_TIMEOUT;
147 /* Reading pipe buffer */
148 while (1) {
149 usleep(1200);
151 struct epoll_event events[max_events];
152 int num_fds = epoll_wait(efd, events, max_events, -1);
154 clk = log_current_utime;
155 if (!h) {
156 h = config->hosts;
159 for (i = 0; i < num_fds; i++) {
160 target = mk_logger_match(events[i].data.fd);
162 if (!target) {
163 printf("\nERROR matching host/epoll_fd");
164 fflush(stdout);
165 continue;
168 err = ioctl(target->fd, FIONREAD, &bytes);
169 if (err == -1) {
170 perror("err");
174 if (bytes < buffer_limit && clk <= timeout) {
175 break;
177 else {
178 timeout = clk + MK_LOGFILE_TIMEOUT;
179 flog = open(target->target, O_WRONLY | O_CREAT, 0644);
181 if (flog == -1) {
182 printf("\n* error: check your logfile file permission");
183 perror("open");
184 continue;
187 lseek(flog, 0, SEEK_END);
188 slen = splice(events[i].data.fd, NULL, flog,
189 NULL, bytes, SPLICE_F_MOVE);
190 if (slen == -1) {
191 perror("splice");
193 close(flog);
199 struct mk_iov *mk_logger_iov_get()
201 return pthread_getspecific(mk_cache_iov_log);
204 void mk_logger_iov_free(struct mk_iov *iov)
206 mk_iov_free_marked(iov);
209 /* Registra en archivos de logs: accesos
210 y errores */
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 if (log->status != S_LOG_ON) {
220 return 0;
223 iov = mk_logger_iov_get();
225 sched = mk_sched_get_thread_conf();
226 conx = mk_sched_get_connection(sched, cr->socket);
228 /* client IP address */
229 mk_iov_add_entry(iov, conx->ipv4.data, conx->ipv4.len,
230 mk_logfile_iov_dash, MK_IOV_NOT_FREE_BUF);
232 /* Date/time when object was requested */
233 mk_iov_add_entry(iov, log_current_time.data, log_current_time.len,
234 mk_iov_space, MK_IOV_NOT_FREE_BUF);
236 /* Register a successfull request */
237 if (log->final_response == M_HTTP_OK
238 || log->final_response == M_REDIR_MOVED_T) {
239 /* HTTP method required */
240 method = mk_http_method_check_str(log->method);
241 mk_iov_add_entry(iov, method.data, method.len, mk_iov_space,
242 MK_IOV_NOT_FREE_BUF);
244 /* HTTP URI required */
245 mk_iov_add_entry(iov, log->uri.data, log->uri.len,
246 mk_iov_space, MK_IOV_NOT_FREE_BUF);
249 if (log->protocol) {
250 protocol = mk_http_protocol_check_str(log->protocol);
251 mk_iov_add_entry(iov, protocol.data, protocol.len,
252 mk_iov_space, MK_IOV_NOT_FREE_BUF);
255 /* HTTP status code */
256 status = (mk_pointer *)
257 mk_http_status_get(log->final_response);
258 mk_iov_add_entry(iov, status->data, status->len,
259 mk_iov_space, MK_IOV_NOT_FREE_BUF);
261 /* object size */
262 mk_iov_add_entry(iov,
263 log->size_p.data,
264 log->size_p.len, mk_iov_lf, MK_IOV_NOT_FREE_BUF);
266 /* Send info to pipe */
267 mk_iov_send(h->log_access[1], iov, MK_IOV_SEND_TO_PIPE);
269 else { /* Register some error */
270 mk_iov_add_entry(iov,
271 log->error_msg.data,
272 log->error_msg.len, mk_iov_space, MK_IOV_NOT_FREE_BUF);
274 /* Check for error extra details */
275 if (log->error_details.data) {
276 mk_iov_add_entry(iov,
277 log->error_details.data,
278 log->error_details.len,
279 mk_iov_lf,
280 MK_IOV_NOT_FREE_BUF);
282 else{
283 mk_iov_add_entry(iov, mk_iov_lf.data,
284 mk_iov_lf.len, mk_iov_none, MK_IOV_NOT_FREE_BUF);
287 mk_iov_send(h->log_error[1], iov, MK_IOV_SEND_TO_PIPE);
289 mk_logger_iov_free(iov);
290 return 0;
293 /* Write Monkey's PID */
294 int mk_logger_register_pid()
296 FILE *pid_file;
298 remove(config->pid_file_path);
299 config->pid_status = VAR_OFF;
300 if ((pid_file = fopen(config->pid_file_path, "w")) == NULL) {
301 puts("Error: I can't log pid of monkey");
302 exit(1);
304 fprintf(pid_file, "%i", getpid());
305 fclose(pid_file);
306 config->pid_status = VAR_ON;
308 return 0;
311 /* Elimina log del PID */
312 int mk_logger_remove_pid()
314 mk_user_undo_uidgid();
315 return remove(config->pid_file_path);