allow to change the logging style; introduce some new ones

add `log style <style>'; The old default is called `legacy' now, a
new default format is added called `condensed', and `common' and
`combined' to mimick Apache httpd and nginx (respectively) are also
added.
This commit is contained in:
Omar Polo 2023-07-25 20:07:26 +00:00
parent 2a28b04424
commit abd261d25b
5 changed files with 142 additions and 8 deletions

67
gmid.c
View File

@ -84,11 +84,23 @@ void
log_request(struct client *c, int code, const char *meta)
{
struct conf *conf = c->conf;
char tstamp[64], rfc3339[32];
char b[GEMINI_URL_LEN];
char *fmted;
const char *t;
struct tm *tm;
time_t now;
int ec;
if ((now = time(NULL)) == -1)
fatal("time");
if ((tm = localtime(&now)) == NULL)
fatal("localtime");
if (strftime(tstamp, sizeof(tstamp), "%d/%b%Y:%H:%M:%S %z", tm) == 0)
fatal("strftime");
if (strftime(rfc3339, sizeof(rfc3339), "%FT%T%z", tm) == 0)
fatal("strftime");
if (c->iri.schema != NULL) {
/* serialize the IRI */
strlcpy(b, c->iri.schema, sizeof(b));
@ -114,8 +126,59 @@ log_request(struct client *c, int code, const char *meta)
strlcpy(b, t, sizeof(b));
}
ec = asprintf(&fmted, "%s:%s GET %s %d %s", c->rhost, c->rserv, b,
code, meta);
switch (conf->log_format) {
case LOG_FORMAT_LEGACY:
ec = asprintf(&fmted, "%s:%s GET %s %d %s", c->rhost,
c->rserv, b, code, meta);
break;
case LOG_FORMAT_CONDENSED:
/*
* XXX the first '-' is the remote user name, we
* could use the client cert for it.
*
* XXX it should log the size of the response
*/
ec = asprintf(&fmted, "%s %s - %s %s 0 %d %s", rfc3339,
c->rhost, *c->domain == '\0' ? c->iri.host : c->domain,
b, code, meta);
break;
/*
* Attempt to be compatible with the default Apache httpd'
* LogFormat "%h %l %u %t \"%r\" %>s %b"
* see <https://httpd.apache.org/docs/current/mod/mod_log_config.html>
*/
case LOG_FORMAT_COMMON:
/*
* XXX the second '-' is the remote user name, we
* could use the client cert for it.
*
* XXX it should log the size of the response.
*/
ec = asprintf(&fmted, "%s %s - - %s \"%s\" %d 0",
*c->domain == '\0' ? c->iri.host : c->domain,
c->rhost, tstamp, b, code);
break;
/*
* Attempt to be compatible with the default nginx' log_format
* combined:
* '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
*/
case LOG_FORMAT_COMBINED:
default:
/*
* XXX the second '-' is the remote user name, we
* could use the client cert for it.
*
* XXX it should log the size of the response.
*/
ec = asprintf(&fmted, "%s - - [%s] \"%s\" %d 0 \"-\" \"\"",
c->rhost, tstamp, b, code);
break;
}
if (ec == -1)
fatal("asprintf");

View File

@ -142,6 +142,51 @@ Log the requests to
.Ar file .
The path is relative to the
.Ic chroot .
.It Ic style Ar style
Set the logging style, defaults to
.Ic condensed .
The
.Ar style
can be one of:
.Bl -tag -width Ds
.It Ic common
Attempt to be compatible with the default Apache httpd log format.
Each line is formatted as follows: the matching host name,
the remote IP address, one dash
.Sq - ,
Common Name of the client certificate
.Pq if provided, '-' otherwise ,
the timestamp of the request, the request URI wrapped in double quotes,
the response code and the size of the response.
.It Ic combined
Attempt to be compatible with the default nginx log format.
Each line is formatted as follows: the remote IP address, one dash
.Sq - ,
Common Name of the client certificate
.Pq if provided, '-' otherwise ,
the timestamp wrapped in square brackets, the request URI wrapped in
double quotes, the response code, the size of the response, a dash
wrapped in double quotes and "".
The strangness of these two last fields is because Gemini doesn't have
the notion of the
.Dq Referer
header nor the
.Dq User-agent .
.It Ic condensed
The native
.Xr gmid 8
format since 2.0.
Each line is formatted as follows: RFC 3339 date time,
remote IP address, Common Name of the client certificate
.Pq if provided, '-' otherwise ,
the matching host name, the request URI, the size of the response,
the response code and meta.
.It Ic legacy
The pre-2.0 gmid native format.
Each line is formatted as follows: the remote IP address and port, the
.Sq GET
keyword, the request URI, the response code and meta.
.El
.El
.It Ic prefork Ar number
Run the specified number of server processes.

8
gmid.h
View File

@ -90,6 +90,13 @@
struct privsep;
struct privsep_proc;
enum log_format {
LOG_FORMAT_CONDENSED,
LOG_FORMAT_COMMON,
LOG_FORMAT_COMBINED,
LOG_FORMAT_LEGACY,
};
struct parser {
char *iri;
struct iri *parsed;
@ -242,6 +249,7 @@ struct conf {
int prefork;
int reload;
char *log_access;
enum log_format log_format;
int use_privsep_crypto;
struct fcgihead fcgi;

23
parse.y
View File

@ -124,16 +124,16 @@ typedef struct {
%token ACCESS ALIAS AUTO
%token BLOCK
%token CA CERT CHROOT CLIENT
%token CA CERT CHROOT CLIENT COMBINED COMMON CONDENSED
%token DEFAULT
%token FASTCGI FOR_HOST
%token INCLUDE INDEX IPV6
%token KEY
%token LANG LISTEN LOCATION LOG
%token LANG LEGACY LISTEN LOCATION LOG
%token OCSP OFF ON
%token PARAM PORT PREFORK PROTO PROTOCOLS PROXY
%token RELAY_TO REQUIRE RETURN ROOT
%token SERVER SNI SOCKET STRIP SYSLOG
%token SERVER SNI SOCKET STRIP STYLE SYSLOG
%token TCP TOEXT TYPE TYPES
%token USE_TLS USER
%token VERIFYNAME
@ -268,6 +268,18 @@ logopt : SYSLOG {
free(conf->log_access);
conf->log_access = $2;
}
| STYLE COMMON {
conf->log_format = LOG_FORMAT_COMMON;
}
| STYLE COMBINED {
conf->log_format = LOG_FORMAT_COMBINED;
}
| STYLE CONDENSED {
conf->log_format = LOG_FORMAT_CONDENSED;
}
| STILE LEGACY {
conf->log_format = LOG_FORMAT_LEGACY;
}
;
vhost : SERVER string {
@ -603,6 +615,9 @@ static const struct keyword {
{"cert", CERT},
{"chroot", CHROOT},
{"client", CLIENT},
{"combined", COMBINED},
{"common", COMMON},
{"condensed", CONDENSED},
{"default", DEFAULT},
{"fastcgi", FASTCGI},
{"for-host", FOR_HOST},
@ -611,6 +626,7 @@ static const struct keyword {
{"ipv6", IPV6},
{"key", KEY},
{"lang", LANG},
{"legacy", LEGACY},
{"listen", LISTEN},
{"location", LOCATION},
{"log", LOG},
@ -631,6 +647,7 @@ static const struct keyword {
{"sni", SNI},
{"socket", SOCKET},
{"strip", STRIP},
{"style", STYLE},
{"syslog", SYSLOG},
{"tcp", TCP},
{"to-ext", TOEXT},

View File

@ -385,10 +385,11 @@ test_log_file() {
fetch_hdr /
check_reply '20 text/gemini'
# remove the <ip>:<port> leading part
awk '{$1 = ""; print substr($0, 2)}' log > log.edited
# remove the date and ip
awk '{$1 = ""; $2 = ""; print substr($0, 3)}' log > log.edited
echo GET gemini://localhost/ 20 text/gemini | cmp -s - log.edited
printf '%s\n' '- localhost gemini://localhost/ 0 20 text/gemini' \
| cmp -s - log.edited
if [ $? -ne 0 ]; then
# keep the log for post-mortem analysis
return 1