Files
recycled-ni-neutrino/src/nhttpd/yhttpd_mods/mod_weblog.cpp
Stefan Seyfried 61bae2e705 fix build with gcc-4.4.x by adding necessary #includes
git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@56 e54a6e83-5905-42d5-8d5c-058d10e6a962


Origin commit data
------------------
Branch: ni/coolstream
Commit: 601e6b00fc
Author: Stefan Seyfried <seife@tuxbox-git.slipkontur.de>
Date: 2009-12-16 (Wed, 16 Dec 2009)



------------------
This commit was generated by Migit
2009-12-16 08:49:21 +00:00

366 lines
12 KiB
C++

//=============================================================================
// YHTTPD
// mod_weblog : Logging of HTTPD-Requests/Responses
//-----------------------------------------------------------------------------
// Normally
//=============================================================================
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "mod_weblog.h"
#include "helper.h"
//=============================================================================
// Initialization of static variables
//=============================================================================
pthread_mutex_t CmWebLog::WebLog_mutex = PTHREAD_MUTEX_INITIALIZER;
FILE *CmWebLog::WebLogFile = NULL;
int CmWebLog::RefCounter = 0;
std::string CmWebLog::WebLogFilename=LOG_FILE;
std::string CmWebLog::LogFormat =LOG_FORMAT;
//=============================================================================
// Constructor & Destructor
//=============================================================================
CmWebLog::CmWebLog(void)
{
pthread_mutex_lock(&WebLog_mutex); // yea, its mine
RefCounter++;
pthread_mutex_unlock(&WebLog_mutex);
}
//-----------------------------------------------------------------------------
CmWebLog::~CmWebLog(void)
{
pthread_mutex_lock(&WebLog_mutex); // yea, its mine
--RefCounter;
if(RefCounter <= 0)
CloseLogFile();
pthread_mutex_unlock(&WebLog_mutex);
}
//=============================================================================
// HOOKS
//=============================================================================
//-----------------------------------------------------------------------------
// HOOK: Hook_EndConnection
//-----------------------------------------------------------------------------
THandleStatus CmWebLog::Hook_EndConnection(CyhookHandler *hh)
{
if(LogFormat == "CLF")
AddLogEntry_CLF(hh);
else if(LogFormat == "ELF")
AddLogEntry_ELF(hh);
return HANDLED_CONTINUE; // even on Log-Error: continue
}
//-----------------------------------------------------------------------------
// HOOK: Hook_ReadConfig
// This hook ist called from ReadConfig
//-----------------------------------------------------------------------------
THandleStatus CmWebLog::Hook_ReadConfig(CConfigFile *Config, CStringList &ConfigList)
{
LogFormat = Config->getString("mod_weblog.log_format", LOG_FORMAT);
WebLogFilename = Config->getString("mod_weblog.logfile", LOG_FILE);
return HANDLED_CONTINUE;
}
//-----------------------------------------------------------------------------
bool CmWebLog::OpenLogFile()
{
if(WebLogFilename == "")
return false;
if(WebLogFile == NULL)
{
bool isNew = false;
pthread_mutex_lock(&WebLog_mutex); // yeah, its mine
if(access(WebLogFilename.c_str(), 4) != 0)
isNew = true;
WebLogFile = fopen(WebLogFilename.c_str(),"a");
if(isNew)
{
if(LogFormat == "ELF")
{
printf("#Version: 1.0\n");
printf("#Remarks: yhttpd" WEBSERVERNAME "\n");
printf("#Fields: c-ip username date time x-request cs-uri sc-status cs-method bytes time-taken x-time-request x-time-response cached\n");
}
}
pthread_mutex_unlock(&WebLog_mutex);
}
return (WebLogFile != NULL);
}
//-----------------------------------------------------------------------------
void CmWebLog::CloseLogFile()
{
if(WebLogFile != NULL)
{
pthread_mutex_lock(&WebLog_mutex); // yeah, its mine
fclose(WebLogFile);
WebLogFile = NULL;
pthread_mutex_unlock(&WebLog_mutex);
}
}
//-----------------------------------------------------------------------------
#define bufferlen 1024*8
bool CmWebLog::printf(const char *fmt, ...)
{
if(!OpenLogFile())
return false;
bool success = false;
char buffer[bufferlen];
if(WebLogFile != NULL)
{
pthread_mutex_lock(&WebLog_mutex); // yeah, its mine
va_list arglist;
va_start( arglist, fmt );
// if(arglist)
vsnprintf( buffer, bufferlen, fmt, arglist );
va_end(arglist);
unsigned int len = strlen(buffer);
success = (fwrite(buffer, len, 1, WebLogFile) == len);
fflush(WebLogFile);
pthread_mutex_unlock(&WebLog_mutex);
}
return success;
}
//-----------------------------------------------------------------------------
// CLF - Common Logfile Format
//
// Example: 127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
//
// The common logfile format is as follows:
// remotehost rfc931 authuser [date] "request" status bytes
//
// remotehost: Remote hostname (or IP number if DNS hostname is not available, or if DNSLookup is Off.
// rfc931: The remote logname of the user.
// authuser: The username as which the user has authenticated himself.
// [date]: Date and time of the request.
// "request": The request line exactly as it came from the client.
// status: The HTTP status code returned to the client.
// bytes: The content-length of the document transferred.
//-----------------------------------------------------------------------------
void CmWebLog::AddLogEntry_CLF(CyhookHandler *hh)
{
std::string cs_method;
switch (hh->Method)
{
case M_GET: cs_method = "GET"; break;
case M_POST: cs_method = "POST"; break;
case M_HEAD: cs_method = "HEAD"; break;
default:
cs_method = "unknown";
break;
}
std::string c_ip = hh->UrlData["clientaddr"].c_str();
std::string request_startline = hh->UrlData["startline"].c_str();
int s_status = hh->httpStatus;
int bytes = hh->GetContentLength();
struct tm *time_now;
time_t now = time(NULL);
char request_time[80];
time_now = localtime(&now);
strftime(request_time, 80, "[%d/%b/%Y:%H:%M:%S]", time_now);
printf("%s - - %s \"%s\" %d %d\n",
c_ip.c_str(),
request_time,
request_startline.c_str(),
s_status,
bytes);
}
//-----------------------------------------------------------------------------
/*
Definition: (ELF) Extended Log File Format
W3C Working Draft WD-logfile-960323 (http://www.w3.org/pub/WWW/TR/WD-logfile-960323.html)
An extended log file contains a sequence of lines containing ASCII
characters terminated by either the sequence LF or CRLF.
Log file generators should follow the line termination convention for
the platform on which they are executed. Analyzers should accept either form.
Each line may contain either a directive or an entry.
Entries consist of a sequence of fields relating to a single HTTP
transaction. Fields are separated by whitespace, the use of tab characters
for this purpose is encouraged. If a field is unused in a particular
entry dash "-" marks the omitted field. Directives record information about
the logging process itself.
Lines beginning with the # character contain directives.
The following directives are defined:
- Version: <integer>.<integer>
The version of the extended log file format used.
This draft defines version 1.0.
- Fields: [<specifier>...]
Specifies the fields recorded in the log.
- Software: string
Identifies the software which generated the log.
- Start-Date: <date> <time>
The date and time at which the log was started.
- End-Date:<date> <time>
The date and time at which the log was finished.
- Date:<date> <time>
The date and time at which the entry was added.
- Remark: <text>
Comment information. Data recorded in this field should be
ignored by analysis tools.
The directives Version and Fields are required and should precede all
entries in the log. The Fields directive specifies the data recorded in the
fields of each entry.
//-----------------------------------------------------------------------------
Example
The following is an example file in the extended log format:
#Version: 1.0
#Date: 12-Jan-1996 00:00:00
#Fields: time cs-method cs-uri
00:34:23 GET /foo/bar.html
12:21:16 GET /foo/bar.html
12:45:52 GET /foo/bar.html
12:57:34 GET /foo/bar.html
//-----------------------------------------------------------------------------
Fields
The #Fields directive lists a sequence of field identifiers specifying
the information recorded in each entry. Field identifiers may have one
of the following forms:
- identifier
Identifier relates to the transaction as a whole.
- prefix-identifier
Identifier relates to information transfer between parties
defined by the value prefix.
- prefix(header)
Identifies the value of the HTTP header field header for transfer
between parties defined by the value prefix. Fields specified in
this manner always have the value <string>.
The following prefixes are defined:
c : Client
s : Server
r : Remote
cs : Client to Server.
sc : Server to Client.
sr : Server to Remote Server, this prefix is used by proxies.
rs : Remote Server to Server, this prefix is used by proxies.
x : Application specific identifier.
The identifier cs-method thus refers to the method in the request
sent by the client to the server while sc(Referer) refers to the
referer: field of the reply. The identifier c-ip refers to the
client's ip address.
Identifiers. (The following identifiers do not require a prefix)
date : Date at which transaction completed, field has type <date>
time : Time at which transaction completed, field has type <time>
time-taken : Time taken for transaction to complete in
seconds, field has type <fixed>
bytes : bytes transferred, field has type <integer>
cached : Records whether a cache hit occurred, field
has type <integer> 0 indicates a cache miss.
Identifiers. (The following identifiers require a prefix)
ip : IP address and port, field has type <address>
dns : DNS name, field has type <name>
status : Status code, field has type <integer>
comment : Comment returned with status code, field has type <text>
method : Method, field has type <name>
uri : URI, field has type <uri>
uri-stem : Stem portion alone of URI (omitting query), field has type <uri>
uri-query : Query portion alone of URI, field has type <uri>
Special fields for log summaries.
Analysis tools may generate log summaries. A log summary entry begins with a count specifying the number of times a particular even occurred. For example a site may be interested in a count of the number of requests for a particular URI with a given referer: field but not be interested in recording information about individual requests such as the IP address.
The following field is mandatory and must precede all others:
count
The number of entries for which the listed data, field has type <integer>
The following fields may be used in place of time to allow aggregation of log file entries over intervals of time.
time-from
Time at which sampling began, field has type <time>
time-to
Time at which sampling ended, field has type <time>
interval
Time over which sampling occurred in seconds, field has type <integer>
-----------------------------------------------------------------------------
actual Implementation:
c-ip
date
tile
request
cs-uri
sc-status
cs-method
bytes
time-taken
x-time-request
x-time-response
cached
*/
void CmWebLog::AddLogEntry_ELF(CyhookHandler *hh)
{
std::string cs_method;
switch (hh->Method)
{
case M_GET: cs_method = "GET"; break;
case M_POST: cs_method = "POST"; break;
case M_HEAD: cs_method = "HEAD"; break;
default:
cs_method = "unknown";
break;
}
std::string c_ip = hh->UrlData["clientaddr"].c_str();
std::string request_startline = hh->UrlData["startline"].c_str();
std::string cs_uri = hh->UrlData["fullurl"];
std::string cs_uri_stem = hh->UrlData["url"];
int sc_status = hh->httpStatus;
int bytes = hh->GetContentLength();
int cached = (hh->HookVarList["CacheCategory"].empty()) ? 0 : 1;
struct tm *time_now;
time_t now = time(NULL);
time_now = localtime(&now);
char request_time[80];
strftime(request_time, 80, "[%d/%b/%Y:%H:%M:%S]", time_now);
char _date[11];
strftime(_date, 11, "%Y-%m-%d", time_now);
char _time[11];
strftime(_time, 11, "%H:%M:%S", time_now);
std::string time_taken_request = hh->HookVarList["enlapsed_request"];
std::string time_taken_response = hh->HookVarList["enlapsed_response"];
long time_taken = atoi(time_taken_request.c_str()) + atoi(time_taken_response.c_str());
printf("%s %s %s \"%s\" %s %d %s %d %ld %s %s %d\n",
c_ip.c_str(),
_date,
_time,
request_startline.c_str(),
cs_uri.c_str(),
sc_status,
cs_method.c_str(),
bytes,
time_taken,
time_taken_request.c_str(),
time_taken_response.c_str(),
cached
);
}