diff --git a/filebeat/docs/fields.asciidoc b/filebeat/docs/fields.asciidoc index 05ac09dce9a0..92912a780cca 100644 --- a/filebeat/docs/fields.asciidoc +++ b/filebeat/docs/fields.asciidoc @@ -18,6 +18,7 @@ grouped in the following categories: * <> * <> * <> +* <> * <> * <> * <> @@ -1427,6 +1428,357 @@ Type -- +[[exported-fields-haproxy]] +== haproxy fields + +haproxy Module + + + +[float] +== haproxy fields + + + + +*`haproxy.process_name`*:: ++ +-- +Name of the process + +-- + +*`haproxy.pid`*:: ++ +-- +type: long + +Process ID + +-- + +*`haproxy.client_ip`*:: ++ +-- +client_ip is the IP address of the client which initiated the TCP connection to haproxy. + +-- + +*`haproxy.client_port`*:: ++ +-- +type: long + +client_port is the TCP port of the client which initiated the connection. + +-- + +*`haproxy.frontend_name`*:: ++ +-- +frontend_name is the name of the frontend (or listener) which received and processed the connection. + +-- + +*`haproxy.backend_name`*:: ++ +-- +backend_name is the name of the backend (or listener) which was selected to manage the connection to the server. + +-- + +*`haproxy.server_name`*:: ++ +-- +server_name is the name of the last server to which the connection was sent. + +-- + +*`haproxy.time_client_req`*:: ++ +-- +type: long + +time_client_req is the total time in milliseconds spent waiting for a full HTTP request from the client (not counting body) after the first byte was received. + +-- + +*`haproxy.time_queue`*:: ++ +-- +type: long + +time_queue is the total time in milliseconds spent waiting in the various queues. + +-- + +*`haproxy.time_backend_connect`*:: ++ +-- +type: long + +time_backend_connect is the total time in milliseconds spent waiting for the connection to establish to the final server, including retries. + +-- + +*`haproxy.time_server_response`*:: ++ +-- +type: long + +time_server_response is the total time in milliseconds spent waiting for the server to send a full HTTP response, not counting data. + +-- + +*`haproxy.time_duration`*:: ++ +-- +type: long + +time_duration is the time the request remained active in haproxy, which is the total time in milliseconds elapsed between the first byte of the request was received and the last byte of response was sent. + +-- + +*`haproxy.server_queue`*:: ++ +-- +type: long + +server_queue is the total number of requests which were processed before this one in the server queue. + +-- + +*`haproxy.backend_queue`*:: ++ +-- +type: long + +backend_queue is the total number of requests which were processed before this one in the backend's global queue. + +-- + +*`haproxy.bind_name`*:: ++ +-- + + +-- + +*`haproxy.error_message`*:: ++ +-- +type: text + +error_message is the error message logged by HAProxy in case of error. + +-- + +[float] +== geoip fields + +Contains GeoIP information gathered based on the client_ip field. Only present if the GeoIP Elasticsearch plugin is available and used. + + + +*`haproxy.geoip.continent_name`*:: ++ +-- +type: keyword + +The name of the continent. + + +-- + +*`haproxy.geoip.country_iso_code`*:: ++ +-- +type: keyword + +Country ISO code. + + +-- + +*`haproxy.geoip.location`*:: ++ +-- +type: geo_point + +The longitude and latitude. + + +-- + +*`haproxy.geoip.region_name`*:: ++ +-- +type: keyword + +The region name. + + +-- + +*`haproxy.geoip.city_name`*:: ++ +-- +type: keyword + +The city name. + + +-- + +*`haproxy.geoip.region_iso_code`*:: ++ +-- +type: keyword + +Region ISO code. + + +-- + +*`haproxy.termination_state`*:: ++ +-- +termination_state is the condition the session was in when the session ended. + +-- + +[float] +== connections fields + +Contains various counts of connections active in the process. + + +*`haproxy.connections.active`*:: ++ +-- +type: long + +active is the total number of concurrent connections on the process when the session was logged. + +-- + +*`haproxy.connections.frontend`*:: ++ +-- +type: long + +frontend is the total number of concurrent connections on the frontend when the session was logged. + +-- + +*`haproxy.connections.backend`*:: ++ +-- +type: long + +backend is the total number of concurrent connections handled by the backend when the session was logged. + +-- + +*`haproxy.connections.server`*:: ++ +-- +type: long + +server is the total number of concurrent connections still active on the server when the session was logged. + +-- + +*`haproxy.connections.retries`*:: ++ +-- +type: long + +retries is the number of connection retries experienced by this session when trying to connect to the server. + +-- + +[float] +== http fields + +Please add description + + +[float] +== response fields + +Fields related to the HTTP response + + +*`haproxy.http.response.status_code`*:: ++ +-- +type: long + +status_code is the HTTP status code returned to the client. + +-- + +*`haproxy.http.response.bytes_read`*:: ++ +-- +type: long + +bytes_read is the total number of bytes transmitted to the client when the log is emitted. + +-- + +*`haproxy.http.response.captured_cookie`*:: ++ +-- +captured_cookie is an optional "name=value" entry indicating that the client had this cookie in the response. + + +-- + +*`haproxy.http.response.captured_headers`*:: ++ +-- +type: text + +captured_response_headers is a list of headers captured in the response due to the presence of the "capture response header" statement in the frontend. + + +-- + +[float] +== request fields + +Fields related to the HTTP request + + +*`haproxy.http.request.captured_cookie`*:: ++ +-- +captured_cookie is an optional "name=value" entry indicating that the server has returned a cookie with its request. + + +-- + +*`haproxy.http.request.captured_headers`*:: ++ +-- +type: text + +captured_request_headers is a list of headers captured in the request due to the presence of the "capture request header" statement in the frontend. + + +-- + +*`haproxy.http.request.raw_request_line`*:: ++ +-- +type: text + +raw_request_line is the complete HTTP request line, including the method, request and HTTP version string. + +-- + [[exported-fields-host-processor]] == Host fields diff --git a/filebeat/docs/images/kibana-haproxy-overview.png b/filebeat/docs/images/kibana-haproxy-overview.png new file mode 100644 index 000000000000..85a24bf01f3a Binary files /dev/null and b/filebeat/docs/images/kibana-haproxy-overview.png differ diff --git a/filebeat/docs/modules/haproxy.asciidoc b/filebeat/docs/modules/haproxy.asciidoc new file mode 100644 index 000000000000..08461f50c570 --- /dev/null +++ b/filebeat/docs/modules/haproxy.asciidoc @@ -0,0 +1,62 @@ +//// +This file is generated! See scripts/docs_collector.py +//// + +[[filebeat-module-haproxy]] +:modulename: haproxy + +== haproxy module + +The +{modulename}+ module collects and parses logs from a (`haproxy`) process. + +include::../include/what-happens.asciidoc[] + +[float] +=== Compatibility + +The +{modulename}+ module was tested with logs from `haproxy` running on AWS Linux as a gateway to a cluster of microservices. + +This module is not available for Windows. + +include::../include/running-modules.asciidoc[] + +[float] +=== Example dashboard + +This module comes with a sample dashboard showing geolocation, distribution of requests between backends and frontends, +and status codes over time. For example: + +[role="screenshot"] +image::./images/kibana-haproxy-overview.png[] + +include::../include/configuring-intro.asciidoc[] + +The module is by default configured to run via syslog on port 9001. However +it can also be configured to read from a file path. See the following example. + +["source","yaml",subs="attributes"] +----- +- module: haproxy + http: + enabled: true + var.paths: ["/var/log/haproxy.log"] + var.input: "file" +----- + +:fileset_ex: http + +include::../include/config-option-intro.asciidoc[] + + +[float] +==== `http` log fileset settings + +include::../include/var-paths.asciidoc[] + + +[float] +=== Fields + +For a description of each field in the module, see the +<> section. + diff --git a/filebeat/docs/modules_list.asciidoc b/filebeat/docs/modules_list.asciidoc index 02764b903684..cab4413edbe0 100644 --- a/filebeat/docs/modules_list.asciidoc +++ b/filebeat/docs/modules_list.asciidoc @@ -6,6 +6,7 @@ This file is generated! See scripts/docs_collector.py * <> * <> * <> + * <> * <> * <> * <> @@ -27,6 +28,7 @@ include::modules-overview.asciidoc[] include::modules/apache2.asciidoc[] include::modules/auditd.asciidoc[] include::modules/elasticsearch.asciidoc[] +include::modules/haproxy.asciidoc[] include::modules/icinga.asciidoc[] include::modules/iis.asciidoc[] include::modules/kafka.asciidoc[] diff --git a/filebeat/filebeat.reference.yml b/filebeat/filebeat.reference.yml index f1265d5be43d..631a0eea5f04 100644 --- a/filebeat/filebeat.reference.yml +++ b/filebeat/filebeat.reference.yml @@ -116,6 +116,19 @@ filebeat.modules: # Filebeat will choose the paths depending on your OS. #var.paths: +#------------------------------- haproxy Module ------------------------------ +- module: haproxy + # All logs + http: + enabled: true + + # Set which input to use between syslog (default) or file. + #var.input: + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + #------------------------------- Icinga Module ------------------------------- #- module: icinga # Main logs diff --git a/filebeat/include/fields.go b/filebeat/include/fields.go index fda0f3f48415..e87e986dd908 100644 --- a/filebeat/include/fields.go +++ b/filebeat/include/fields.go @@ -31,5 +31,5 @@ func init() { // Asset returns asset data func Asset() string { - return "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" + return "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" } diff --git a/filebeat/module/haproxy/_meta/config.yml b/filebeat/module/haproxy/_meta/config.yml new file mode 100644 index 000000000000..5071f0fccd80 --- /dev/null +++ b/filebeat/module/haproxy/_meta/config.yml @@ -0,0 +1,11 @@ +- module: haproxy + # All logs + http: + enabled: true + + # Set which input to use between syslog (default) or file. + #var.input: + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: diff --git a/filebeat/module/haproxy/_meta/docs.asciidoc b/filebeat/module/haproxy/_meta/docs.asciidoc new file mode 100644 index 000000000000..bb0111ca19c1 --- /dev/null +++ b/filebeat/module/haproxy/_meta/docs.asciidoc @@ -0,0 +1,49 @@ +:modulename: haproxy + +== haproxy module + +The +{modulename}+ module collects and parses logs from a (`haproxy`) process. + +include::../include/what-happens.asciidoc[] + +[float] +=== Compatibility + +The +{modulename}+ module was tested with logs from `haproxy` running on AWS Linux as a gateway to a cluster of microservices. + +This module is not available for Windows. + +include::../include/running-modules.asciidoc[] + +[float] +=== Example dashboard + +This module comes with a sample dashboard showing geolocation, distribution of requests between backends and frontends, +and status codes over time. For example: + +[role="screenshot"] +image::./images/kibana-haproxy-overview.png[] + +include::../include/configuring-intro.asciidoc[] + +The module is by default configured to run via syslog on port 9001. However +it can also be configured to read from a file path. See the following example. + +["source","yaml",subs="attributes"] +----- +- module: haproxy + http: + enabled: true + var.paths: ["/var/log/haproxy.log"] + var.input: "file" +----- + +:fileset_ex: http + +include::../include/config-option-intro.asciidoc[] + + +[float] +==== `http` log fileset settings + +include::../include/var-paths.asciidoc[] diff --git a/filebeat/module/haproxy/_meta/fields.yml b/filebeat/module/haproxy/_meta/fields.yml new file mode 100644 index 000000000000..88a2e576a6b7 --- /dev/null +++ b/filebeat/module/haproxy/_meta/fields.yml @@ -0,0 +1,127 @@ +- key: haproxy + title: "haproxy" + description: > + haproxy Module + fields: + - name: haproxy + type: group + description: > + fields: + - name: process_name + description: Name of the process + + - name: pid + description: Process ID + type: long + + - name: client_ip + description: client_ip is the IP address of the client which initiated the TCP connection to haproxy. + + - name: client_port + description: client_port is the TCP port of the client which initiated the connection. + type: long + + - name: frontend_name + description: frontend_name is the name of the frontend (or listener) which received and processed the connection. + + - name: backend_name + description: backend_name is the name of the backend (or listener) which was selected to manage the connection to the server. + + - name: server_name + description: server_name is the name of the last server to which the connection was sent. + + - name: time_client_req + description: time_client_req is the total time in milliseconds spent waiting for a full HTTP request from the client (not counting body) after the first byte was received. + type: long + + - name: time_queue + description: time_queue is the total time in milliseconds spent waiting in the various queues. + type: long + + - name: time_backend_connect + description: time_backend_connect is the total time in milliseconds spent waiting for the connection to establish to the final server, including retries. + type: long + + - name: time_server_response + description: time_server_response is the total time in milliseconds spent waiting for the server to send a full HTTP response, not counting data. + type: long + + - name: time_duration + description: time_duration is the time the request remained active in haproxy, which is the total time in milliseconds elapsed between the first byte of the request was received and the last byte of response was sent. + type: long + + - name: server_queue + description: server_queue is the total number of requests which were processed before this one in the server queue. + type: long + + - name: backend_queue + description: backend_queue is the total number of requests which were processed before this one in the backend's global queue. + type: long + + - name: bind_name + description: > + + - name: error_message + description: error_message is the error message logged by HAProxy in case of error. + type: text + + - name: geoip + type: group + description: > + Contains GeoIP information gathered based on the client_ip field. + Only present if the GeoIP Elasticsearch plugin is available and + used. + fields: + - name: continent_name + type: keyword + description: > + The name of the continent. + - name: country_iso_code + type: keyword + description: > + Country ISO code. + - name: location + type: geo_point + description: > + The longitude and latitude. + - name: region_name + type: keyword + description: > + The region name. + - name: city_name + type: keyword + description: > + The city name. + - name: region_iso_code + type: keyword + description: > + Region ISO code. + + - name: termination_state + description: termination_state is the condition the session was in when the session ended. + + - name: connections + description: Contains various counts of connections active in the process. + type: group + fields: + - name: active + description: active is the total number of concurrent connections on the process when the session was logged. + type: long + + - name: frontend + description: frontend is the total number of concurrent connections on the frontend when the session was logged. + type: long + + - name: backend + description: backend is the total number of concurrent connections handled by the backend when the session was logged. + type: long + + - name: server + description: server is the total number of concurrent connections still active on the server when the session was logged. + type: long + + - name: retries + description: retries is the number of connection retries experienced by this session when trying to connect to the server. + type: long + + diff --git a/filebeat/module/haproxy/_meta/kibana/default/dashboard/Filebeat-haproxy-overview.json b/filebeat/module/haproxy/_meta/kibana/default/dashboard/Filebeat-haproxy-overview.json new file mode 100644 index 000000000000..9ea04c9018b0 --- /dev/null +++ b/filebeat/module/haproxy/_meta/kibana/default/dashboard/Filebeat-haproxy-overview.json @@ -0,0 +1,406 @@ +{ + "objects": [ + { + "attributes": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [], + "index": "filebeat-*", + "query": { + "language": "lucene", + "query": "" + } + } + }, + "title": "Backend breakdown [Filebeat HAProxy]", + "uiStateJSON": {}, + "version": 1, + "visState": { + "aggs": [ + { + "enabled": true, + "id": "1", + "params": {}, + "schema": "metric", + "type": "count" + }, + { + "enabled": true, + "id": "2", + "params": { + "field": "haproxy.backend_name", + "missingBucket": false, + "missingBucketLabel": "Missing", + "order": "desc", + "orderBy": "1", + "otherBucket": false, + "otherBucketLabel": "Other", + "size": 5 + }, + "schema": "segment", + "type": "terms" + } + ], + "params": { + "addLegend": true, + "addTooltip": true, + "isDonut": true, + "labels": { + "last_level": true, + "show": false, + "truncate": 100, + "values": true + }, + "legendPosition": "right", + "type": "pie" + }, + "title": "Backend breakdown [Filebeat HAProxy]", + "type": "pie" + } + }, + "id": "55251360-aa32-11e8-9c06-877f0445e3e0", + "type": "visualization", + "updated_at": "2018-08-27T19:50:02.901Z", + "version": 2 + }, + { + "attributes": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [], + "index": "filebeat-*", + "query": { + "language": "lucene", + "query": "" + } + } + }, + "title": "Frontend breakdown [Filebeat HAProxy]", + "uiStateJSON": {}, + "version": 1, + "visState": { + "aggs": [ + { + "enabled": true, + "id": "1", + "params": {}, + "schema": "metric", + "type": "count" + }, + { + "enabled": true, + "id": "2", + "params": { + "field": "haproxy.frontend_name", + "missingBucket": false, + "missingBucketLabel": "Missing", + "order": "desc", + "orderBy": "1", + "otherBucket": false, + "otherBucketLabel": "Other", + "size": 5 + }, + "schema": "segment", + "type": "terms" + } + ], + "params": { + "addLegend": true, + "addTooltip": true, + "isDonut": true, + "labels": { + "last_level": true, + "show": false, + "truncate": 100, + "values": true + }, + "legendPosition": "right", + "type": "pie" + }, + "title": "Frontend breakdown [Filebeat HAProxy]", + "type": "pie" + } + }, + "id": "7fb671f0-aa32-11e8-9c06-877f0445e3e0", + "type": "visualization", + "updated_at": "2018-08-27T19:50:50.255Z", + "version": 1 + }, + { + "attributes": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [], + "index": "filebeat-*", + "query": { + "language": "lucene", + "query": "" + } + } + }, + "title": "IP Geohashes [Filebeat HAProxy]", + "uiStateJSON": { + "mapCenter": [ + -9.275622176792098, + 28.4765625 + ], + "mapZoom": 2 + }, + "version": 1, + "visState": { + "aggs": [ + { + "enabled": true, + "id": "1", + "params": { + "field": "haproxy.client_ip" + }, + "schema": "metric", + "type": "cardinality" + }, + { + "enabled": true, + "id": "2", + "params": { + "autoPrecision": true, + "field": "haproxy.geoip.location", + "isFilteredByCollar": true, + "precision": 2, + "useGeocentroid": true + }, + "schema": "segment", + "type": "geohash_grid" + } + ], + "params": { + "addTooltip": true, + "heatClusterSize": 1.5, + "isDesaturated": true, + "legendPosition": "bottomright", + "mapCenter": [ + 0, + 0 + ], + "mapType": "Scaled Circle Markers", + "mapZoom": 2, + "wms": { + "baseLayersAreLoaded": { + "_c": [], + "_d": true, + "_h": 0, + "_n": false, + "_s": 1, + "_v": true + }, + "enabled": false, + "options": { + "format": "image/png", + "transparent": true + }, + "selectedTmsLayer": { + "attribution": "\u003cp\u003e\u0026#169; \u003ca href=\"http://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors | \u003ca href=\"https://www.elastic.co/elastic-maps-service\"\u003eElastic Maps Service\u003c/a\u003e\u003c/p\u003e\u0026#10;", + "id": "road_map", + "maxZoom": 18, + "minZoom": 0, + "subdomains": [], + "url": "https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree\u0026my_app_name=kibana\u0026my_app_version=6.3.2\u0026license=222b9c80-1528-4ddf-9a40-cc59d57f55bf" + }, + "tmsLayers": [ + { + "attribution": "\u003cp\u003e\u0026#169; \u003ca href=\"http://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors | \u003ca href=\"https://www.elastic.co/elastic-maps-service\"\u003eElastic Maps Service\u003c/a\u003e\u003c/p\u003e\u0026#10;", + "id": "road_map", + "maxZoom": 18, + "minZoom": 0, + "subdomains": [], + "url": "https://tiles.maps.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree\u0026my_app_name=kibana\u0026my_app_version=6.3.2\u0026license=222b9c80-1528-4ddf-9a40-cc59d57f55bf" + } + ] + } + }, + "title": "IP Geohashes [Filebeat HAProxy]", + "type": "tile_map" + } + }, + "id": "11f8b9c0-aa32-11e8-9c06-877f0445e3e0", + "type": "visualization", + "updated_at": "2018-08-27T19:49:15.098Z", + "version": 2 + }, + { + "attributes": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [], + "index": "filebeat-*", + "query": { + "language": "lucene", + "query": "" + } + } + }, + "title": "Response codes over time [Filebeat HAProxy]", + "uiStateJSON": { + "vis": { + "colors": { + "200": "#508642", + "204": "#629E51", + "302": "#6ED0E0", + "404": "#EAB839", + "503": "#705DA0" + } + } + }, + "version": 1, + "visState": { + "aggs": [ + { + "enabled": true, + "id": "1", + "params": {}, + "schema": "metric", + "type": "count" + }, + { + "enabled": true, + "id": "2", + "params": { + "customInterval": "2h", + "extended_bounds": {}, + "field": "@timestamp", + "interval": "auto", + "min_doc_count": 1 + }, + "schema": "segment", + "type": "date_histogram" + }, + { + "enabled": true, + "id": "3", + "params": { + "field": "haproxy.http.response.status_code", + "missingBucket": false, + "missingBucketLabel": "Missing", + "order": "desc", + "orderBy": "_term", + "otherBucket": false, + "otherBucketLabel": "Other", + "size": 5 + }, + "schema": "group", + "type": "terms" + } + ], + "params": { + "addLegend": true, + "addTimeMarker": false, + "addTooltip": true, + "categoryAxes": [ + { + "id": "CategoryAxis-1", + "labels": { + "show": true, + "truncate": 100 + }, + "position": "bottom", + "scale": { + "type": "linear" + }, + "show": true, + "style": {}, + "title": {}, + "type": "category" + } + ], + "grid": { + "categoryLines": false, + "style": { + "color": "#eee" + } + }, + "legendPosition": "right", + "seriesParams": [ + { + "data": { + "id": "1", + "label": "Count" + }, + "drawLinesBetweenPoints": true, + "mode": "stacked", + "show": "true", + "showCircles": true, + "type": "histogram", + "valueAxis": "ValueAxis-1" + } + ], + "times": [], + "type": "histogram", + "valueAxes": [ + { + "id": "ValueAxis-1", + "labels": { + "filter": false, + "rotate": 0, + "show": true, + "truncate": 100 + }, + "name": "LeftAxis-1", + "position": "left", + "scale": { + "mode": "normal", + "type": "linear" + }, + "show": true, + "style": {}, + "title": { + "text": "Count" + }, + "type": "value" + } + ] + }, + "title": "Response codes over time [Filebeat HAProxy]", + "type": "histogram" + } + }, + "id": "68af8ef0-aa33-11e8-9c06-877f0445e3e0", + "type": "visualization", + "updated_at": "2018-08-27T19:57:55.070Z", + "version": 2 + }, + { + "attributes": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": { + "filter": [], + "highlightAll": true, + "query": { + "language": "lucene", + "query": "" + }, + "version": true + } + }, + "optionsJSON": { + "darkTheme": false, + "hidePanelTitles": false, + "useMargins": true + }, + "panelsJSON": null, + "timeRestore": false, + "title": "[Filebeat HAProxy] Overview", + "version": 1 + }, + "id": "3560d580-aa34-11e8-9c06-877f0445e3e0", + "type": "dashboard", + "updated_at": "2018-08-27T20:03:04.536Z", + "version": 1 + } + ], + "version": "6.3.2" +} \ No newline at end of file diff --git a/filebeat/module/haproxy/http/_meta/fields.yml b/filebeat/module/haproxy/http/_meta/fields.yml new file mode 100644 index 000000000000..630075299b43 --- /dev/null +++ b/filebeat/module/haproxy/http/_meta/fields.yml @@ -0,0 +1,44 @@ +- name: http + description: Please add description + type: group + fields: + - name: response + description: Fields related to the HTTP response + type: group + fields: + - name: status_code + description: status_code is the HTTP status code returned to the client. + type: long + + - name: bytes_read + description: bytes_read is the total number of bytes transmitted to the client when the log is emitted. + type: long + + - name: captured_cookie + description: > + captured_cookie is an optional "name=value" entry indicating that the client had this cookie in the response. + + - name: captured_headers + description: > + captured_response_headers is a list of headers captured in the response due to the presence of the "capture response header" statement in the frontend. + type: text + + - name: request + description: Fields related to the HTTP request + type: group + fields: + - name: captured_cookie + description: > + captured_cookie is an optional "name=value" entry indicating that the server has returned a cookie with its request. + + - name: captured_headers + description: > + captured_request_headers is a list of headers captured in the request due to the presence of the "capture request header" statement in the frontend. + type: text + + - name: raw_request_line + description: raw_request_line is the complete HTTP request line, including the method, request and HTTP version string. + type: text + + + diff --git a/filebeat/module/haproxy/http/config/file.yml b/filebeat/module/haproxy/http/config/file.yml new file mode 100644 index 000000000000..0afd17317d4f --- /dev/null +++ b/filebeat/module/haproxy/http/config/file.yml @@ -0,0 +1,6 @@ +type: log +paths: +{{ range $i, $path := .paths }} + - {{$path}} +{{ end }} +exclude_files: [".gz$"] diff --git a/filebeat/module/haproxy/http/config/syslog.yml b/filebeat/module/haproxy/http/config/syslog.yml new file mode 100644 index 000000000000..c5c3fba1eee5 --- /dev/null +++ b/filebeat/module/haproxy/http/config/syslog.yml @@ -0,0 +1,3 @@ +type: syslog +protocol.udp: + host: "localhost:{{.syslog_port}}" diff --git a/filebeat/module/haproxy/http/ingest/pipeline.json b/filebeat/module/haproxy/http/ingest/pipeline.json new file mode 100644 index 000000000000..8b1807edded3 --- /dev/null +++ b/filebeat/module/haproxy/http/ingest/pipeline.json @@ -0,0 +1,52 @@ +{ + "description": "Pipeline for parsing HAProxy http logs in their default format. Requires the geoip plugin.", + "processors": [{ + "grok": { + "field": "message", + "patterns": [ + "(%{NOTSPACE:haproxy.process_name}\\[%{NUMBER:haproxy.pid:int}\\]: )?%{IP:haproxy.client_ip}:%{NUMBER:haproxy.client_port:int} \\[%{NOTSPACE:haproxy.http.request_date}\\] %{NOTSPACE:haproxy.frontend_name} %{NOTSPACE:haproxy.backend_name}/%{NOTSPACE:haproxy.server_name} %{NUMBER:haproxy.time_client_req:int}/%{NUMBER:haproxy.time_queue:int}/%{NUMBER:haproxy.time_backend_connect:int}/%{NUMBER:haproxy.time_server_response:int}/%{NUMBER:haproxy.time_duration:int} %{NUMBER:haproxy.http.response.status_code:int} %{NUMBER:haproxy.http.response.bytes_read:int} %{NOTSPACE:haproxy.http.request.captured_cookie} %{NOTSPACE:haproxy.http.response.captured_cookie} %{NOTSPACE:haproxy.termination_state} %{NUMBER:haproxy.connections.active:int}/%{NUMBER:haproxy.connections.frontend:int}/%{NUMBER:haproxy.connections.backend:int}/%{NUMBER:haproxy.connections.server:int}/%{NUMBER:haproxy.connections.retries:int} %{NUMBER:haproxy.server_queue:int}/%{NUMBER:haproxy.backend_queue:int} \\{%{DATA:haproxy.http.request.captured_headers}\\} \\{%{DATA:haproxy.http.response.captured_headers}\\} \"%{GREEDYDATA:haproxy.http.request.raw_request_line}\"", + "(%{NOTSPACE:haproxy.process_name}\\[%{NUMBER:haproxy.pid:int}\\]: )?%{IP:haproxy.client_ip}:%{NUMBER:haproxy.client_port:int} \\[%{NOTSPACE:haproxy.http.request_date}\\] %{NOTSPACE:haproxy.frontend_name}/%{NOTSPACE:haproxy.bind_name} %{GREEDYDATA:haproxy.error_message}" + ], + "ignore_missing": false + } + }, + { + "date": { + "field": "haproxy.http.request_date", + "target_field": "@timestamp", + "formats": ["dd/MMM/yyyy:HH:mm:ss.SSS"] + } + }, + { + "remove": { + "field": "haproxy.http.request_date" + } + }, + { + "geoip": { + "field": "haproxy.client_ip", + "target_field": "haproxy.geoip" + } + }, + { + "split": { + "field": "haproxy.http.request.captured_headers", + "separator": "\\|", + "ignore_failure": true + } + }, + { + "split": { + "field": "haproxy.http.response.captured_headers", + "separator": "\\|", + "ignore_failure": true + } + } + ], + "on_failure" : [{ + "set" : { + "field" : "error.message", + "value" : "{{ _ingest.on_failure_message }}" + } + }] +} diff --git a/filebeat/module/haproxy/http/manifest.yml b/filebeat/module/haproxy/http/manifest.yml new file mode 100644 index 000000000000..a50c2c3dede7 --- /dev/null +++ b/filebeat/module/haproxy/http/manifest.yml @@ -0,0 +1,13 @@ +module_version: 1.0 + +var: + - name: paths + default: + - /var/log/haproxy.log + - name: syslog_port + default: 9001 + - name: input + default: syslog + +ingest_pipeline: ingest/pipeline.json +input: config/{{.input}}.yml diff --git a/filebeat/module/haproxy/http/test/haproxy.log b/filebeat/module/haproxy/http/test/haproxy.log new file mode 100644 index 000000000000..ad3550d19c9c --- /dev/null +++ b/filebeat/module/haproxy/http/test/haproxy.log @@ -0,0 +1 @@ +Jul 30 09:03:52 localhost haproxy[32450]: 1.2.3.4:38862 [30/Jul/2018:09:03:52.726] incoming~ docs_microservice/docs 0/0/1/0/2 304 168 - - ---- 6/6/0/0/0 0/0 {docs.example.internal||} {|||} "GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1" diff --git a/filebeat/module/haproxy/http/test/haproxy.log-expected.json b/filebeat/module/haproxy/http/test/haproxy.log-expected.json new file mode 100644 index 000000000000..551ac0bb3075 --- /dev/null +++ b/filebeat/module/haproxy/http/test/haproxy.log-expected.json @@ -0,0 +1,47 @@ +[ + { + "haproxy.server_name": "docs", + "haproxy.time_client_req": 0, + "haproxy.geoip.continent_name": "North America", + "haproxy.geoip.city_name": "Mukilteo", + "haproxy.geoip.country_iso_code": "US", + "haproxy.geoip.region_name": "Washington", + "haproxy.geoip.location.lon": -122.3042, + "haproxy.geoip.location.lat": 47.913, + "haproxy.termination_state": "----", + "haproxy.time_queue": 0, + "haproxy.pid": 32450, + "haproxy.client_port": 38862, + "haproxy.backend_queue": 0, + "haproxy.process_name": "haproxy", + "haproxy.backend_name": "docs_microservice", + "haproxy.http.request.raw_request_line": "GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1", + "haproxy.http.request.captured_cookie": "-", + "haproxy.http.request.captured_headers": [ + "docs.example.internal" + ], + "haproxy.http.response.captured_cookie": "-", + "haproxy.http.response.captured_headers": [], + "haproxy.http.response.status_code": 304, + "haproxy.http.response.bytes_read": 168, + "haproxy.frontend_name": "incoming~", + "haproxy.time_duration": 2, + "haproxy.time_server_response": 0, + "haproxy.server_queue": 0, + "haproxy.client_ip": "1.2.3.4", + "haproxy.time_backend_connect": 1, + "haproxy.connections.server": 0, + "haproxy.connections.retries": 0, + "haproxy.connections.active": 6, + "haproxy.connections.backend": 0, + "haproxy.connections.frontend": 6, + "@timestamp": "2018-07-30T09:03:52.726Z", + "message": "Jul 30 09:03:52 localhost haproxy[32450]: 1.2.3.4:38862 [30/Jul/2018:09:03:52.726] incoming~ docs_microservice/docs 0/0/1/0/2 304 168 - - ---- 6/6/0/0/0 0/0 {docs.example.internal||} {|||} \"GET /component---src-pages-index-js-4b15624544f97cf0bb8f.js HTTP/1.1\"", + "input.type": "log", + "prospector.type": "log", + "fileset.module": "haproxy", + "fileset.name": "http", + "haproxy.geoip.region_iso_code": "US-WA", + "offset": 0 + } +] diff --git a/filebeat/module/haproxy/module.yml b/filebeat/module/haproxy/module.yml new file mode 100644 index 000000000000..c8023c7d1e22 --- /dev/null +++ b/filebeat/module/haproxy/module.yml @@ -0,0 +1,3 @@ +dashboards: +- id: Filebeat-haproxy-overview-dashboard + file: Filebeat-haproxy-overview.json diff --git a/filebeat/modules.d/haproxy.yml.disabled b/filebeat/modules.d/haproxy.yml.disabled new file mode 100644 index 000000000000..5071f0fccd80 --- /dev/null +++ b/filebeat/modules.d/haproxy.yml.disabled @@ -0,0 +1,11 @@ +- module: haproxy + # All logs + http: + enabled: true + + # Set which input to use between syslog (default) or file. + #var.input: + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: