140 lines
3.9 KiB
Nix
140 lines
3.9 KiB
Nix
{
|
|
flake-inputs,
|
|
pkgs,
|
|
config,
|
|
lib,
|
|
...
|
|
}:
|
|
let
|
|
hostNames = lib.attrNames config.services.nginx.virtualHosts;
|
|
logPath = name: "/var/log/nginx/${name}/access.log";
|
|
logFormat = lib.concatStringsSep " " [
|
|
"$remote_addr - $remote_user [$time_local]"
|
|
''"$request" $status $body_bytes_sent''
|
|
''"$http_referer" "$http_user_agent"''
|
|
''rt=$request_time uct="$upstream_connect_time"''
|
|
''uht="$upstream_header_time" urt="$upstream_response_time"''
|
|
];
|
|
in
|
|
{
|
|
# Extend the default configuration for nginx virtual hosts; we'd
|
|
# like to create log files for each of them, so that the prometheus
|
|
# nginxlog exporter can process per-host logs.
|
|
options.services.nginx.virtualHosts = lib.mkOption {
|
|
type = lib.types.attrsOf (
|
|
lib.types.submodule (
|
|
{ name, ... }:
|
|
{
|
|
config.extraConfig = ''
|
|
access_log ${logPath name} upstream_time;
|
|
'';
|
|
}
|
|
)
|
|
);
|
|
};
|
|
|
|
config = {
|
|
# Create directories for host-specific logs with systemd tmpfiles
|
|
systemd.tmpfiles.settings."10-nginx-logs" = lib.listToAttrs (
|
|
map (
|
|
name:
|
|
lib.nameValuePair "/var/log/nginx/${name}" {
|
|
d = {
|
|
inherit (config.services.nginx) user group;
|
|
mode = "0750";
|
|
};
|
|
}
|
|
) hostNames
|
|
);
|
|
|
|
services = {
|
|
# Set the nginx-wide log format
|
|
nginx.commonHttpConfig = ''
|
|
log_format upstream_time '${logFormat}';
|
|
'';
|
|
|
|
# Set up nginxlog to read the file and log format defined above
|
|
# for each virtual host
|
|
prometheus.exporters.nginxlog = {
|
|
enable = true;
|
|
listenAddress = "127.0.0.1";
|
|
group = "nginx";
|
|
|
|
settings.namespaces = map (name: {
|
|
inherit name;
|
|
metrics_override.prefix = "nginxlog";
|
|
namespace_label = "vhost";
|
|
format = logFormat;
|
|
source.files = [ (logPath name) ];
|
|
}) hostNames;
|
|
};
|
|
|
|
logrotate.settings = {
|
|
# Override the nginx module default, just keep fewer logs
|
|
nginx.rotate = 6;
|
|
|
|
# Configure logrotate for host-specific logs
|
|
nginxVirtualHosts = {
|
|
files = map logPath hostNames;
|
|
|
|
frequency = "daily";
|
|
rotate = 2;
|
|
compress = true;
|
|
delaycompress = true;
|
|
su = "${config.services.nginx.user} ${config.services.nginx.group}";
|
|
postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
|
|
};
|
|
};
|
|
};
|
|
|
|
serviceTests =
|
|
let
|
|
testHostConfig =
|
|
{ config, ... }:
|
|
{
|
|
imports = [
|
|
./.
|
|
../../modules/serviceTests/mocks.nix
|
|
];
|
|
|
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
|
|
|
services.nginx = {
|
|
domain = "testHost";
|
|
virtualHosts."${config.services.nginx.domain}".locations."/".return = "200 ok";
|
|
};
|
|
};
|
|
in
|
|
{
|
|
nginxMetricsWork = pkgs.testers.runNixOSTest {
|
|
name = "nginx-metrics-work";
|
|
node.specialArgs = { inherit flake-inputs; };
|
|
|
|
nodes = {
|
|
testHost = testHostConfig;
|
|
|
|
client =
|
|
{ pkgs, ... }:
|
|
{
|
|
environment.systemPackages = [ pkgs.curl ];
|
|
};
|
|
};
|
|
|
|
testScript = ''
|
|
import time
|
|
|
|
start_all()
|
|
|
|
testHost.wait_for_unit("nginx.service")
|
|
client.succeed("curl --max-time 10 http://testHost")
|
|
|
|
# Wait a bit for the prometheus exporter to scrape our logs
|
|
time.sleep(5)
|
|
|
|
res = testHost.succeed("curl localhost:${builtins.toString config.services.prometheus.exporters.nginxlog.port}/metrics")
|
|
assert 'nginxlog_http_response_count_total{method="GET",status="200",vhost="testHost"} 1' in res, res
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
}
|