1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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.
26 #include <arpa/inet.h>
27 #include <netinet/in.h>
33 #include <sys/ioctl.h>
35 #include <sys/types.h>
37 #include <sys/times.h>
41 #include "http_status.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
));
76 struct log_target
*mk_logger_match(int fd
)
78 struct log_target
*aux
;
93 void *mk_logger_worker_init(void *args
)
95 int efd
, max_events
= config
->nhosts
;
97 struct log_target
*target
= 0;
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)
119 * it means the maximum data that a monkey log pipe can contain.
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
);
128 efd
= mk_epoll_create(max_events
);
132 /* Add access log file */
133 if( h
->log_access
[0] > 0 ) {
134 mk_epoll_add_client(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_client(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
);
147 timeout
= time(NULL
) + MK_LOGFILE_TIMEOUT
;
149 /* Reading pipe buffer */
153 struct epoll_event events
[max_events
];
154 int num_fds
= epoll_wait(efd
, events
, max_events
, -1);
156 clk
= log_current_utime
;
161 for (i
= 0; i
< num_fds
; i
++) {
162 target
= mk_logger_match(events
[i
].data
.fd
);
165 printf("\nERROR matching host/epoll_fd");
170 err
= ioctl(target
->fd
, FIONREAD
, &bytes
);
175 if (bytes
< buffer_limit
&& clk
<= timeout
) {
179 timeout
= clk
+ MK_LOGFILE_TIMEOUT
;
180 flog
= open(target
->target
, O_WRONLY
| O_CREAT
, 0644);
183 printf("\n* error: check your logfile file permission");
188 lseek(flog
, 0, SEEK_END
);
189 slen
= splice(events
[i
].data
.fd
, NULL
, flog
,
190 NULL
, bytes
, SPLICE_F_MOVE
);
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
,
215 mk_pointer
*status
, method
, protocol
;
216 struct sched_list_node
*sched
;
217 struct sched_connection
*conx
;
220 MK_TRACE("Logger, Writting to log file [FD %i]", cr
->socket
);
223 if (log
->status
!= S_LOG_ON
) {
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
);
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
);
270 if (log
->size_p
.data
) {
271 mk_iov_add_entry(iov
,
273 log
->size_p
.len
, mk_iov_none
, MK_IOV_NOT_FREE_BUF
);
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
,
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
,
293 MK_IOV_NOT_FREE_BUF
);
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
);
306 /* Write Monkey's PID */
307 int mk_logger_register_pid()
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");
317 fprintf(pid_file
, "%i", getpid());
319 config
->pid_status
= VAR_ON
;
324 /* Remove PID file */
325 int mk_logger_remove_pid()
327 mk_user_undo_uidgid();
328 return remove(config
->pid_file_path
);