linuxPackages_latest.broadcom_sta: add patch to compile on Kernel 6.12 (#359484)
[NixPkgs.git] / nixos / modules / services / logging / awstats.nix
blobd6d1fd64bd52ad72f343244522b672508e5d475e
1 { config, lib, pkgs, ... }:
2 let
3   cfg = config.services.awstats;
4   package = pkgs.awstats;
5   configOpts = {name, config, ...}: {
6     options = {
7       type = lib.mkOption{
8         type = lib.types.enum [ "mail" "web" ];
9         default = "web";
10         example = "mail";
11         description = ''
12           The type of log being collected.
13         '';
14       };
15       domain = lib.mkOption {
16         type = lib.types.str;
17         default = name;
18         description = "The domain name to collect stats for.";
19         example = "example.com";
20       };
22       logFile = lib.mkOption {
23         type = lib.types.str;
24         example = "/var/log/nginx/access.log";
25         description = ''
26           The log file to be scanned.
28           For mail, set this to
29           ```
30           journalctl $OLD_CURSOR -u postfix.service | ''${pkgs.perl}/bin/perl ''${pkgs.awstats.out}/share/awstats/tools/maillogconvert.pl standard |
31           ```
32         '';
33       };
35       logFormat = lib.mkOption {
36         type = lib.types.str;
37         default = "1";
38         description = ''
39           The log format being used.
41           For mail, set this to
42           ```
43           %time2 %email %email_r %host %host_r %method %url %code %bytesd
44           ```
45         '';
46       };
48       hostAliases = lib.mkOption {
49         type = lib.types.listOf lib.types.str;
50         default = [];
51         example = [ "www.example.org" ];
52         description = ''
53           List of aliases the site has.
54         '';
55       };
57       extraConfig = lib.mkOption {
58         type = lib.types.attrsOf lib.types.str;
59         default = {};
60         example = lib.literalExpression ''
61           {
62             "ValidHTTPCodes" = "404";
63           }
64         '';
65         description = "Extra configuration to be appended to awstats.\${name}.conf.";
66       };
68       webService = {
69         enable = lib.mkEnableOption "awstats web service";
71         hostname = lib.mkOption {
72           type = lib.types.str;
73           default = config.domain;
74           description = "The hostname the web service appears under.";
75         };
77         urlPrefix = lib.mkOption {
78           type = lib.types.str;
79           default = "/awstats";
80           description = "The URL prefix under which the awstats pages appear.";
81         };
82       };
83     };
84   };
85   webServices = lib.filterAttrs (name: value: value.webService.enable) cfg.configs;
88   imports = [
89     (lib.mkRemovedOptionModule [ "services" "awstats" "service" "enable" ] "Please enable per domain with `services.awstats.configs.<name>.webService.enable`")
90     (lib.mkRemovedOptionModule [ "services" "awstats" "service" "urlPrefix" ] "Please set per domain with `services.awstats.configs.<name>.webService.urlPrefix`")
91     (lib.mkRenamedOptionModule [ "services" "awstats" "vardir" ] [ "services" "awstats" "dataDir" ])
92   ];
94   options.services.awstats = {
95     enable = lib.mkEnableOption "awstats, a real-time logfile analyzer";
97     dataDir = lib.mkOption {
98       type = lib.types.path;
99       default = "/var/lib/awstats";
100       description = "The directory where awstats data will be stored.";
101     };
103     configs = lib.mkOption {
104       type = lib.types.attrsOf (lib.types.submodule configOpts);
105       default = {};
106       example = lib.literalExpression ''
107         {
108           "mysite" = {
109             domain = "example.com";
110             logFile = "/var/log/nginx/access.log";
111           };
112         }
113       '';
114       description = "Attribute set of domains to collect stats for.";
115     };
117     updateAt = lib.mkOption {
118       type = lib.types.nullOr lib.types.str;
119       default = null;
120       example = "hourly";
121       description = ''
122         Specification of the time at which awstats will get updated.
123         (in the format described by {manpage}`systemd.time(7)`)
124       '';
125     };
126   };
129   config = lib.mkIf cfg.enable {
130     environment.systemPackages = [ package.bin ];
132     environment.etc = lib.mapAttrs' (name: opts:
133     lib.nameValuePair "awstats/awstats.${name}.conf" {
134       source = pkgs.runCommand "awstats.${name}.conf"
135       { preferLocalBuild = true; }
136       (''
137         sed \
138       ''
139       # set up mail stats
140       + lib.optionalString (opts.type == "mail")
141       ''
142         -e 's|^\(LogType\)=.*$|\1=M|' \
143         -e 's|^\(LevelForBrowsersDetection\)=.*$|\1=0|' \
144         -e 's|^\(LevelForOSDetection\)=.*$|\1=0|' \
145         -e 's|^\(LevelForRefererAnalyze\)=.*$|\1=0|' \
146         -e 's|^\(LevelForRobotsDetection\)=.*$|\1=0|' \
147         -e 's|^\(LevelForSearchEnginesDetection\)=.*$|\1=0|' \
148         -e 's|^\(LevelForFileTypesDetection\)=.*$|\1=0|' \
149         -e 's|^\(LevelForWormsDetection\)=.*$|\1=0|' \
150         -e 's|^\(ShowMenu\)=.*$|\1=1|' \
151         -e 's|^\(ShowSummary\)=.*$|\1=HB|' \
152         -e 's|^\(ShowMonthStats\)=.*$|\1=HB|' \
153         -e 's|^\(ShowDaysOfMonthStats\)=.*$|\1=HB|' \
154         -e 's|^\(ShowDaysOfWeekStats\)=.*$|\1=HB|' \
155         -e 's|^\(ShowHoursStats\)=.*$|\1=HB|' \
156         -e 's|^\(ShowDomainsStats\)=.*$|\1=0|' \
157         -e 's|^\(ShowHostsStats\)=.*$|\1=HB|' \
158         -e 's|^\(ShowAuthenticatedUsers\)=.*$|\1=0|' \
159         -e 's|^\(ShowRobotsStats\)=.*$|\1=0|' \
160         -e 's|^\(ShowEMailSenders\)=.*$|\1=HBML|' \
161         -e 's|^\(ShowEMailReceivers\)=.*$|\1=HBML|' \
162         -e 's|^\(ShowSessionsStats\)=.*$|\1=0|' \
163         -e 's|^\(ShowPagesStats\)=.*$|\1=0|' \
164         -e 's|^\(ShowFileTypesStats\)=.*$|\1=0|' \
165         -e 's|^\(ShowFileSizesStats\)=.*$|\1=0|' \
166         -e 's|^\(ShowBrowsersStats\)=.*$|\1=0|' \
167         -e 's|^\(ShowOSStats\)=.*$|\1=0|' \
168         -e 's|^\(ShowOriginStats\)=.*$|\1=0|' \
169         -e 's|^\(ShowKeyphrasesStats\)=.*$|\1=0|' \
170         -e 's|^\(ShowKeywordsStats\)=.*$|\1=0|' \
171         -e 's|^\(ShowMiscStats\)=.*$|\1=0|' \
172         -e 's|^\(ShowHTTPErrorsStats\)=.*$|\1=0|' \
173         -e 's|^\(ShowSMTPErrorsStats\)=.*$|\1=1|' \
174       ''
175       +
176       # common options
177       ''
178         -e 's|^\(DirData\)=.*$|\1="${cfg.dataDir}/${name}"|' \
179         -e 's|^\(DirIcons\)=.*$|\1="icons"|' \
180         -e 's|^\(CreateDirDataIfNotExists\)=.*$|\1=1|' \
181         -e 's|^\(SiteDomain\)=.*$|\1="${name}"|' \
182         -e 's|^\(LogFile\)=.*$|\1="${opts.logFile}"|' \
183         -e 's|^\(LogFormat\)=.*$|\1="${opts.logFormat}"|' \
184       ''
185       +
186       # extra config
187       lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
188         -e 's|^\(${n}\)=.*$|\1="${v}"|' \
189       '') opts.extraConfig)
190       +
191       ''
192         < '${package.out}/wwwroot/cgi-bin/awstats.model.conf' > "$out"
193       '');
194     }) cfg.configs;
196     # create data directory with the correct permissions
197     systemd.tmpfiles.rules =
198       [ "d '${cfg.dataDir}' 755 root root - -" ] ++
199       lib.mapAttrsToList (name: opts: "d '${cfg.dataDir}/${name}' 755 root root - -") cfg.configs ++
200       [ "Z '${cfg.dataDir}' 755 root root - -" ];
202     # nginx options
203     services.nginx.virtualHosts = lib.mapAttrs'(name: opts: {
204       name = opts.webService.hostname;
205       value = {
206         locations = {
207           "${opts.webService.urlPrefix}/css/" = {
208             alias = "${package.out}/wwwroot/css/";
209           };
210           "${opts.webService.urlPrefix}/icons/" = {
211             alias = "${package.out}/wwwroot/icon/";
212           };
213           "${opts.webService.urlPrefix}/" = {
214             alias = "${cfg.dataDir}/${name}/";
215             extraConfig = ''
216               autoindex on;
217             '';
218           };
219         };
220       };
221     }) webServices;
223     # update awstats
224     systemd.services = lib.mkIf (cfg.updateAt != null) (lib.mapAttrs' (name: opts:
225       lib.nameValuePair "awstats-${name}-update" {
226         description = "update awstats for ${name}";
227         script = lib.optionalString (opts.type == "mail")
228         ''
229           if [[ -f "${cfg.dataDir}/${name}-cursor" ]]; then
230             CURSOR="$(cat "${cfg.dataDir}/${name}-cursor" | tr -d '\n')"
231             if [[ -n "$CURSOR" ]]; then
232               echo "Using cursor: $CURSOR"
233               export OLD_CURSOR="--cursor $CURSOR"
234             fi
235           fi
236           NEW_CURSOR="$(journalctl $OLD_CURSOR -u postfix.service --show-cursor | tail -n 1 | tr -d '\n' | sed -e 's#^-- cursor: \(.*\)#\1#')"
237           echo "New cursor: $NEW_CURSOR"
238           ${package.bin}/bin/awstats -update -config=${name}
239           if [ -n "$NEW_CURSOR" ]; then
240             echo -n "$NEW_CURSOR" > ${cfg.dataDir}/${name}-cursor
241           fi
242         '' + ''
243           ${package.out}/share/awstats/tools/awstats_buildstaticpages.pl \
244             -config=${name} -update -dir=${cfg.dataDir}/${name} \
245             -awstatsprog=${package.bin}/bin/awstats
246         '';
247         startAt = cfg.updateAt;
248     }) cfg.configs);
249   };