commit - 2a28b0442431d06f1989c9c4861c442bca5c7dcf
commit + abd261d25bdfa01c44d07a9803db669bc62ddf76
blob - d5794340a90748c089d7dd4853c57a1720c94e95
blob + 7f02a965b3c99535ad5e6cb0707305a50aa7b375
--- gmid.c
+++ gmid.c
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));
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");
blob - a3c1b603b10b6c01ada46b854f38e494b12532ec
blob + 58999ba28be31ff75d8b30d617c2dcf37e0ebb77
--- gmid.conf.5
+++ gmid.conf.5
.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.
This increases the performance and prevents delays when connecting to
blob - 734ad54ee4b25530727537e969aaeb313b944ca2
blob + e1805b429d6d3545b4ffa1ccdd1e674f5bca3ef9
--- gmid.h
+++ gmid.h
/* forward declaration */
struct privsep;
struct privsep_proc;
+
+enum log_format {
+ LOG_FORMAT_CONDENSED,
+ LOG_FORMAT_COMMON,
+ LOG_FORMAT_COMBINED,
+ LOG_FORMAT_LEGACY,
+};
struct parser {
char *iri;
int prefork;
int reload;
char *log_access;
+ enum log_format log_format;
int use_privsep_crypto;
struct fcgihead fcgi;
blob - 674437b99bf55b57b54204be396b4a192fc14197
blob + 74b5c96999bbda365eb94af188246653d3baf22e
--- parse.y
+++ parse.y
%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
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 {
{"cert", CERT},
{"chroot", CHROOT},
{"client", CLIENT},
+ {"combined", COMBINED},
+ {"common", COMMON},
+ {"condensed", CONDENSED},
{"default", DEFAULT},
{"fastcgi", FASTCGI},
{"for-host", FOR_HOST},
{"ipv6", IPV6},
{"key", KEY},
{"lang", LANG},
+ {"legacy", LEGACY},
{"listen", LISTEN},
{"location", LOCATION},
{"log", LOG},
{"sni", SNI},
{"socket", SOCKET},
{"strip", STRIP},
+ {"style", STYLE},
{"syslog", SYSLOG},
{"tcp", TCP},
{"to-ext", TOEXT},
blob - 9020103f39852831fb9418fd6405ec23906d6cd2
blob + 4fc9b5913d4b8ccb3940ec86855cd3128b448cdb
--- regress/tests.sh
+++ regress/tests.sh
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