tested on debian12
we here separate access and error logs in two different indices
prepare an index template and eventually a user for that purpose
– make sure you’ve got a template for pattern nginx-*
.
# osearch http://localhost:5601/app/opensearch_index_management_dashboards#/templates
make sure some data nodes are reachable
nmap -p 9200 10.1.0.30 # osearch curl -k https://10.1.0.30:9200/?pretty -u admin:PASSWORD
vi /etc/fluent-bit/fluent-bit.conf
# INDENTATION WITH SPACES NOT TABS [SERVICE] flush 1 daemon off parsers_file parsers.conf parsers_file custom_parsers.conf plugins_file plugins.conf log_file /var/log/fluent-bit.log [INPUT] name tail path /var/log/nginx/*error*log tag nginx.error # https://nginx.org/en/docs/http/ngx_http_log_module.html --> log_format escape=json [INPUT] name tail path /var/log/nginx/*access*log tag nginx.access parser json_no_time # @timestamp is enough [FILTER] name modify match nginx.access remove time_iso8601 # https://elastic.co/guide/en/ecs/1.12/ecs-geo.html [FILTER] name geoip2 match nginx.access database /etc/fluent-bit/GeoLite2-City.mmdb lookup_key remote_addr record geo.city_name remote_addr %{city.names.en} record geo.country_name remote_addr %{country.names.en} record lat remote_addr %{location.latitude} record lon remote_addr %{location.longitude} log_level error # catch lat lon (lat comes first) [FILTER] name nest match nginx.access operation nest wildcard l* nest_under geo.location # https://docs.fluentbit.io/manual/pipeline/filters/parser [FILTER] name parser match nginx.access key_name request parser split_request reserve_data true [FILTER] name parser match nginx.access key_name path parser strip_querystr reserve_data true preserve_key true [FILTER] name modify match nginx.* add sensor nginx@HOSTNAME # mimic k8s/cri [FILTER] name modify match nginx.error add stream stderr [FILTER] name modify match nginx.access add stream stdout [OUTPUT] name file match nginx.* path /var/log file fluent-bit.nginx.log
chmod 600 fluent-bit.conf vi /etc/fluent-bit/custom_parsers.conf
# @timestamp is enough - no time_key # nginx's time_local is a pain to handle anyhow # https://docs.fluentbit.io/manual/pipeline/parsers/configuring-parser [PARSER] name json_no_time format json # split-up the request field [PARSER] name split_request format regex regex ^(?<method>[^ ]*) (?<path>[^ ]*) HTTP/(?<http_version>[^ ]*) # help differenciate web pages - strip out the query string [PARSER] name strip_querystr format regex regex ^(?<page>[^?]*)
tail -F /var/log/fluent-bit*log systemctl restart fluent-bit systemctl status fluent-bit
curl -i localhost # 200 access log curl -i localhost/NO-EXIST # 404 access log
easy-peasy error log generation
# generate an error log - fcgiwrap not installed location ~ (\.cgi|\.sh)$ { fastcgi_pass unix:/var/run/fcgiwrap.socket; } cat > /var/www/html/error.sh <EOF #!/bin/bash echo 'Content-Type: text/html' echo echo '<p>this message should NOT show up -- it should generate an nginx error log instead' EOF
chmod +x error.sh curl -i localhost/error.sh # error log
[ warn] [engine] failed to flush chunk '51468-1698409873.302155692.flb', retry in 9 seconds: task_id=0, input=tail.0 > output=opensearch.0 (out_id=0) [error] [output:opensearch:opensearch.0] HTTP status=401 URI=/_bulk [error] [engine] chunk '51468-1698409873.302155692.flb' cannot be retried: task_id=0, input=tail.0 > output=opensearch.0
https://opensearch.org/blog/getting-started-with-fluent-bit-and-opensearch/
https://docs.fluentbit.io/manual/pipeline/outputs/opensearch
https://opensearch.org/docs/latest/api-reference/index-apis/get-index/
https://opensearch.org/docs/latest/dashboards/discover/index-discover/
https://stackoverflow.com/questions/69617608/elasticsearch-8-errors-with-action-metadata-line-1-contains-an-unknown-paramet ==> nice example
https://docs.oracle.com/en-us/iaas/Content/search-opensearch/Tasks/ingestingfluentbit.htm
https://stackoverflow.com/questions/73867417/opensearch-401-for-bulk ==> don’t forget to authenticate
https://docs.fluentbit.io/manual/pipeline/inputs/nginx