diff options
author | Paul Querna <pquerna@apache.org> | 2018-04-23 17:49:16 +0200 |
---|---|---|
committer | Paul Querna <pquerna@apache.org> | 2018-04-23 17:49:16 +0200 |
commit | 43e8216b894c02b87aad2d969fb9d9c3431280ac (patch) | |
tree | 5646ad9aed2aa6b3dbd97dfb02137ebd76272e4f /modules/loggers | |
parent | Move APACHE_CHECK_JANSSON m4 macro to general includes so additional modules ... (diff) | |
download | apache2-43e8216b894c02b87aad2d969fb9d9c3431280ac.tar.xz apache2-43e8216b894c02b87aad2d969fb9d9c3431280ac.zip |
Add mod_log_json
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1829898 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/loggers')
-rw-r--r-- | modules/loggers/config.m4 | 11 | ||||
-rw-r--r-- | modules/loggers/mod_log_json.c | 169 |
2 files changed, 180 insertions, 0 deletions
diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4 index 30318626ba..f4e908fe24 100644 --- a/modules/loggers/config.m4 +++ b/modules/loggers/config.m4 @@ -36,6 +36,17 @@ APACHE_MODULE(syslog, logging to syslog, , , all, [ fi ]) + +APACHE_MODULE(log_json, logging in jsonn, , , most, [ + APACHE_CHECK_JANSSON + if test "x$ac_cv_jansson" != "xyes" ; then + AC_MSG_WARN([libjansson not found]) + enable_log_json="no" + else + enable_log_json="yes" + fi +]) + APACHE_MODULE(log_config, logging configuration. You won't be able to log requests to the server without this module., , , yes) APACHE_MODULE(log_debug, configurable debug logging, , , most) APACHE_MODULE(log_forensic, forensic logging) diff --git a/modules/loggers/mod_log_json.c b/modules/loggers/mod_log_json.c new file mode 100644 index 0000000000..c7d70d8be1 --- /dev/null +++ b/modules/loggers/mod_log_json.c @@ -0,0 +1,169 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#include "http_request.h" + +#include <mod_ssl.h> +#include <mod_log_config.h> + +#include "apr_strings.h" + +#include <jansson.h> + +APLOG_USE_MODULE(log_json); + +module AP_MODULE_DECLARE_DATA log_json_module; + +static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *log_json_ssl_lookup = NULL; +static APR_OPTIONAL_FN_TYPE(ssl_is_https) *log_json_ssl_is_https = NULL; +static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_json_register = NULL; + +static const char *crit_error = + "{\"mod_log_json_error\": \"critical error during serialization: see error " + "log\"}"; + +static int +log_json_dump_bb(const char *buffer, size_t size, void *baton) +{ + apr_bucket_brigade *bb = baton; + apr_brigade_write(bb, NULL, NULL, buffer, size); + return 0; +} + +static const char * +log_json(request_rec *r, char *a) +{ + apr_size_t olen; + apr_status_t rv; + int err; + char *out; + apr_bucket_brigade *bb; + json_t *obj; + + obj = json_object(); + + json_object_set_new_nocheck(obj, "log_id", + r->log_id != NULL ? json_string(r->log_id) : json_null()); + json_object_set_new_nocheck( + obj, "vhost", json_string(r->server->server_hostname)); + json_object_set_new_nocheck( + obj, "status", json_string(apr_itoa(r->pool, r->status))); + json_object_set_new_nocheck(obj, "proto", json_string(r->protocol)); + json_object_set_new_nocheck(obj, "method", json_string(r->method)); + json_object_set_new_nocheck(obj, "uri", json_string(r->uri)); + json_object_set_new_nocheck(obj, "srcip", json_string(r->useragent_ip)); + json_object_set_new_nocheck(obj, "bytes_sent", json_integer(r->bytes_sent)); + + if (r->user != NULL) { + json_object_set_new_nocheck(obj, "user", json_string(r->user)); + } + + json_t *hdrs = json_object(); + json_object_set_new_nocheck(hdrs, "user-agent", + json_string(apr_table_get(r->headers_in, "User-Agent"))); + json_object_set_new_nocheck(obj, "hdrs", hdrs); + + if (log_json_ssl_is_https != NULL && log_json_ssl_lookup != NULL && + log_json_ssl_is_https(r->connection)) { + json_t *tls = json_object(); + + json_object_set_new_nocheck(tls, "v", + json_string(log_json_ssl_lookup( + r->pool, r->server, r->connection, r, "SSL_PROTOCOL"))); + json_object_set_new_nocheck(tls, "cipher", + json_string(log_json_ssl_lookup( + r->pool, r->server, r->connection, r, "SSL_COPHER"))); + json_object_set_new_nocheck(tls, "client_verify", + json_string(log_json_ssl_lookup( + r->pool, r->server, r->connection, r, "SSL_CLIENT_VERIFY"))); + json_object_set_new_nocheck(tls, "sni", + json_string(log_json_ssl_lookup( + r->pool, r->server, r->connection, r, "SSL_TLS_SNI"))); + + json_object_set_new_nocheck(obj, "tls", tls); + } + + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + err = json_dump_callback( + obj, log_json_dump_bb, bb, JSON_ENSURE_ASCII | JSON_COMPACT); + if (err != 0) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + APLOGNO(10125) "json_dump_callback failed: %d", err); + apr_brigade_destroy(bb); + return crit_error; + } + + rv = apr_brigade_pflatten(bb, &out, &olen, r->pool); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + APLOGNO(10126) "apr_brigade_pflatten failed"); + apr_brigade_destroy(bb); + return crit_error; + } + apr_brigade_destroy(bb); + return out; +} + +static int +log_json_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) +{ + log_json_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); + log_json_register(p, "^JS", log_json, 0); + return OK; +} + +static int +log_json_post_config( + apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +{ + apr_status_t rv; + server_rec *snxt; + void *userdata_data = NULL; + const char *userdata_key = "log_json_init"; + + apr_pool_userdata_get(&userdata_data, userdata_key, s->process->pool); + if (userdata_data == NULL) { + apr_pool_userdata_set((const void *)1, userdata_key, + apr_pool_cleanup_null, s->process->pool); + return OK; + } + + log_json_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); + log_json_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); + + /* http://jansson.readthedocs.io/en/2.8/portability.html#portability-thread-safety + */ + json_object_seed(0); + + return OK; +} + +static const command_rec directives[] = {{NULL}}; + +static void +register_hooks(apr_pool_t *pool) +{ + ap_hook_pre_config(log_json_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config(log_json_post_config, NULL, NULL, APR_HOOK_MIDDLE); +} + +module AP_MODULE_DECLARE_DATA log_json_module = {STANDARD20_MODULE_STUFF, NULL, + NULL, NULL, NULL, directives, register_hooks}; |