Ключевые слова:apache, module, traffic, log, (найти похожие документы)
Date: Wed, 27 Oct 2004 12:23:59 +0400
From: Roman Listov <r2l@maker.ru.>
Subject: Пример apache модуля для подсчета трафика
Прошу прощения, если напрягаю.
Встал тут вопрос подсчета апачевского трафика. После изучения
вопроса было найдено два модуля - mod_watch от snert.com и
mod_accounting. Первый весьма продвинут, но, имхо, тяжеловат и
перегружен опциями... и без настроек результатирующего файлва. дело
в том, что хотелось бы сохранять еще и зону, с которой получен
трафик (и которую выдает мне mod_geo). mod_accounting гораздо
попросче, даже я смог приковырять туда сохранение зоны, но... блин,
валить все в рилтайме в базу... имхо, полный оверхед. В итоге на
основе mod_accounting создал модулек, просто выставляющий переменные
окружения для последующего использования их в LogFormat.
Но так как программирование на Ц у меня в зачаточном состоянии, был
бы благодарен, если бы кто пробежался итог взглядом и указал где я
неправ (хоть модуль и работает, но мало ли что). А может и на другие
подводные камни такого подсчета.
Спасибо!
//#define DEBUG
#include <stdio.h>
#include <stdlib.h>
#include "mod_bytess.h"
#define MOD_BYTESS_VERSION_INFO_STRING "mod_bytess/0.1"
module MODULE_VAR_EXPORT bytess_module;
// hook function pass to ap_table_do()
static int GetHeaderLen( long *count, const char *key, const char *val )
{
*count += strlen( key ) + strlen( val ) + 4; // 4 for ": " + CR + LF
#ifdef DEBUG
ap_log_error( APLOG_MARK, ERRLEVEL, rr->server,
ap_pstrcat( rr->pool, key, ": ", val, NULL ));
#endif
return( 1 );
}
// computes the length of a table
static long TableLen( request_rec *r, table *tab )
{
long count = 0;
if( tab )
ap_table_do((int (*) (void *, const char *, const char *)) GetHeaderLen, (void *) &count, tab, NULL );
return( count );
}
// computes the number of bytes sent
static long BytesSent( request_rec *r )
{
long sent, status_len = 0;
char *custom_response;
#ifdef DEBUG
ap_log_error( APLOG_MARK, ERRLEVEL, rr->server,
"BytesSent" );
#endif
// let's see if it's a failed redirect
// I'm using the same logic of ap_send_error_response()
if( custom_response = (char *)ap_response_code_string( r, ap_index_of_response( r->status ))) {
// if so, find the original request_rec
if( custom_response[0] != '"' )
while( r->prev && ( r->prev->status != HTTP_OK ))
r = r->prev;
}
if( r->status_line )
status_len = strlen( r->status_line );
sent = TableLen( r, r->headers_out ) + TableLen( r, r->err_headers_out ) + 2 + // 2 for CRLF
11 + status_len + // HTTP/1.x nnn blah
10 + strlen( ap_get_server_version() ) + // Server: line
8 + strlen( ap_gm_timestr_822( r->pool, r->request_time )); // Date: line
if(( sent >= 255 ) && ( sent <= 257 ))
sent += sizeof( "X-Pad: avoid browser bug" ) + 1;
if( r->sent_bodyct ) {
if( r->connection ) {
long int bs;
// this is more accurate than bytes_sent in presence of modules
// which manipulate the output (eg. mod_gzip)
ap_bgetopt( r->connection->client, BO_BYTECT, &bs );
sent += bs;
} else
sent += r->bytes_sent;
}
return( sent );
}
// computes the number of bytes received
static long BytesRecvd( request_rec *r )
{
long recvd;
const char *len;
#ifdef DEBUG
ap_log_error( APLOG_MARK, ERRLEVEL, rr->server,
"BytesRecvd" );
#endif
recvd = strlen( r->the_request ) + TableLen( r, r->headers_in ) + 4; // 2 for CRLF after the request, 2 for CRLF after all headers
len = ap_table_get( r->headers_in, "Content-Length" );
if( len )
recvd += atol( len );
return( recvd );
}
// typedef const char *(*hook_func)();
// ------------------- HOOKS -----------------
static int acct_transaction( request_rec *orig )
{
request_rec *r = orig;
// get to the last of the chain, we need the correct byte counters ;-)
while( r->next )
r = r->next;
ap_table_setn(r->subprocess_env, "BYTES_R",
ap_psprintf(r->pool, "%ld", BytesRecvd( orig )) );
ap_table_setn(r->subprocess_env, "BYTES_S",
ap_psprintf(r->pool, "%ld", BytesSent( r )) );
return( OK );
}
static void mod_acct_init( server_rec *server, pool *p )
{
ap_add_version_component(MOD_BYTESS_VERSION_INFO_STRING);
}
// ------------------- MOD CONFIG -----------------
/* The configuration array that sets up the hooks into the module. */
module bytess_module =
{
STANDARD_MODULE_STUFF,
mod_acct_init, /* initializer */
NULL, /* create per-dir config */
NULL, /* merge per-dir config */
NULL, /* server config */
NULL, /* merge server config */
NULL, /* command table */
NULL, /* handlers */
NULL, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
acct_transaction, /* logger */
#if MODULE_MAGIC_NUMBER >= 19970103
NULL, /* header parser */
#endif
#if MODULE_MAGIC_NUMBER >= 19970719
NULL, /* child_init */
#endif
#if MODULE_MAGIC_NUMBER >= 19970728
NULL, /* process exit/cleanup */
#endif
#if MODULE_MAGIC_NUMBER >= 19970902
NULL /* [#0] post read-request */
#endif
};
#ifndef MOD_BYTESS_H
#define MOD_BYTESS_H
#include <time.h>
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "http_core.h"
#define ERRLEVEL (APLOG_ERR|APLOG_NOERRNO)
#define DEBUGLEVEL (APLOG_INFO|APLOG_NOERRNO)
#endif /* MOD_BYTESS_H */