logwatch-7.7/0000775000211400021140000000000014266625341013402 5ustar logwatchlogwatchlogwatch-7.7/amavis-logwatch.10000664000211400021140000010164713076472236016564 0ustar logwatchlogwatch.TH AMAVIS-LOGWATCH 1 .ad .fi .SH NAME amavis-logwatch \- An Amavisd-new log parser and analysis utility .SH "SYNOPSIS" .na .nf .fi \fBamavis-logwatch\fR [\fIoptions\fR] [\fIlogfile ...\fR] .SH DESCRIPTION .ad .fi The \fBamavis-logwatch\fR(1) utility is an Amavisd-new log parser that produces summaries, details, and statistics regarding the operation of Amavisd-new (henceforth, simply called Amavis). .PP This utility can be used as a standalone program, or as a Logwatch filter module to produce Amavisd-new summary and detailed reports from within Logwatch. .PP \fBAmavis-logwatch\fR is able to produce a wide range of reports with data grouped and sorted as much as possible to reduce noise and highlight patterns. Brief summary reports provide a quick overview of general Amavis operations and message delivery, calling out warnings that may require attention. Detailed reports provide easy to scan, hierarchically-arranged and organized information, with as much or little detail as desired. .PP Much of the interesting data is available when Amavis' $log_level is set to at least 2. See \fBAmavis Log Level\fR below. .PP \fBAmavis-logwatch\fR outputs two principal sections: a \fBSummary\fR section and a \fBDetailed\fR section. For readability and quick scanning, all event or hit counts appear in the left column, followed by brief description of the event type, and finally additional statistics or count representations may appear in the rightmost column. The following segment from a sample Summary report illustrates: .RS 4 .nf ****** Summary ******************************************** 9 Miscellaneous warnings 20313 Total messages scanned ---------------- 100.00% 1008.534M Total bytes scanned 1,057,524,252 ======== ================================================ 1190 Blocked ------------------------------- 5.86% 18 Malware blocked 0.09% 4 Banned name blocked 0.02% 416 Spam blocked 2.05% 752 Spam discarded (no quarantine) 3.70% 19123 Passed -------------------------------- 94.14% 47 Bad header passed 0.23% 19076 Clean passed 93.91% ======== ================================================ 18 Malware ------------------------------- 0.09% 18 Malware blocked 0.09% 4 Banned -------------------------------- 0.02% 4 Banned file blocked 0.02% 1168 Spam ---------------------------------- 5.75% 416 Spam blocked 2.05% 752 Spam discarded (no quarantine) 3.70% 19123 Ham ----------------------------------- 94.14% 47 Bad header passed 0.23% 19076 Clean passed 93.91% ======== ================================================ 1982 SpamAssassin bypassed 32 Released from quarantine 2 DSN notification (debug supplemental) 2 Bounce unverifiable 2369 Whitelisted 2 Blacklisted 12 MIME error 58 Bad header (debug supplemental) 40 Extra code modules loaded at runtime .fi .RE 0 The report indicates there were 9 general warnings, and \fBAmavis\fR scanned a total of 20313 messages for a total of 1008.53 megabytes or 1,057,524,252 bytes. The next summary groups shows the Blocked / Passed overview, with 1190 Blocked messages (broken down as 18 messages blocked as malware, 4 messages with banned names, 416 spam messages, and 752 discarded messages), and 19123 Passed messages (47 messages with bad headers and 19076 clean messages). The next (optional) summary grouping shows message disposition by contents category. There were 18 malware messages and 4 banned file messages (all blocked), 1168 Spam messages, of which 416 were blocked (quarantined) and 752 discarded. Finally, there were 19123 messages considered to be Ham (i.e. not spam), 47 of which contained bad headers. Additional count summaries for a variety of events are also listed. .PP There are dozens of sub-sections available in the \fBDetailed\fR report, each of whose output can be controlled in various ways. Each sub-section attempts to group and present the most meaningful data at superior levels, while pushing less useful or \fInoisy\fR data towards inferior levels. The goal is to provide as much benefit as possible from smart grouping of data, to allow faster report scanning, pattern identification, and problem solving. Data is always sorted in descending order by count, and then numerically by IP address or alphabetically as appropriate. .PP The following Spam blocked segment from a sample \fBDetailed\fR report illustrates the basic hierarchical level structure of \fBamavis-logwatch\fR: .RS 4 .nf ****** Detailed ******************************************* 19346 Spam blocked ----------------------------------- 756 from@example.com 12 10.0.0.2 12 <> 12 192.168.2.2 12 <> 5 192.168.2.1 ... .fi .RE 0 .PP The \fBamavis-logwatch\fR utility reads from STDIN or from the named Amavis \fIlogfile\fR. Multiple \fIlogfile\fR arguments may be specified, each processed in order. The user running \fBamavis-logwatch\fR must have read permission on each named log file. .PP .SS Options The options listed below affect the operation of \fBamavis-logwatch\fR. Options specified later on the command line override earlier ones. Any option may be abbreviated to an unambiguous length. .IP "\fB--[no]autolearn\fR" .PD 0 .IP "\fB--show_autolearn \fIboolean\fR" .PD Enables (disables) output of the autolearn report. This report is only available if the default Amavis \fB$log_templ\fR has been modified to provide autolearn results in log entries. This can be done by uncommenting two lines in the Amavis program itself (where the default log templates reside), or by correctly adding the \fB$log_templ\fR variable to the \fBamavisd.conf\fR file. See Amavis' \fBREADME.customize\fR and search near the end of the Amavisd program for "autolearn". .IP "\fB--[no]by_ccat_summary\fR" .PD 0 .IP "\fB--show_by_ccat_summary \fIboolean\fR" .PD Enables (disables) the by contents category summary in the \fBSummary\fR section. Default: enabled. .IP "\fB-f \fIconfig_file\fR" .PD 0 .IP "\fB--config_file \fIconfig_file\fR" .PD Use an alternate configuration file \fIconfig_file\fR instead of the default. This option may be used more than once. Multiple configuration files will be processed in the order presented on the command line. See \fBCONFIGURATION FILE\fR below. .IP "\fB--debug \fIkeywords\fR" Output debug information during the operation of \fBamavis-logwatch\fR. The parameter \fIkeywords\fR is one or more comma or space separated keywords. To obtain the list of valid keywords, use --debug xxx where xxx is any invalid keyword. .IP "\fB--detail \fIlevel\fR" Sets the maximum detail level for \fBamavis-logwatch\fR to \fIlevel\fR. This option is global, overriding any other output limiters described below. The \fBamavis-logwatch\fR utility produces a \fBSummary\fR section, a \fBDetailed\fR section, and additional report sections. With \fIlevel\fR less than 5, \fBamavis-logwatch\fR will produce only the \fBSummary\fR section. At \fIlevel\fR 5 and above, the \fBDetailed\fR section, and any additional report sections are candidates for output. Each incremental increase in \fIlevel\fR generates one additional hierarchical sub-level of output in the \fBDetailed\fR section of the report. At \fIlevel\fR 10, all levels are output. Lines that exceed the maximum report width (specified with \fBmax_report_width\fR) will be cut. Setting \fIlevel\fR to 11 will prevent lines in the report from being cut (see also \fB--line_style\fR). .IP "\fB--[no]first_recip_only\fR" .PD 0 .IP "\fB--show_first_recip_only \fIboolean\fR" .PD Specifies whether or not to sort by, and show, only the first recipient when a scanned messages contains multiple recipients. .IP "\fB--help\fR" Print usage information and a brief description about command line options. .IP "\fB--ipaddr_width \fIwidth\fR" Specifies that IP addresses in address/hostname pairs should be printed with a field width of \fIwidth\fR characters. Increasing the default may be useful for systems using long IPv6 addresses. .IP "\fB-l limiter=levelspec\fR" .PD 0 .IP "\fB--limit limiter=levelspec\fR" .PD Sets the level limiter \fIlimiter\fR with the specification \fIlevelspec\fR. .IP "\fB--line_style \fIstyle\fR" Specifies how to handle long report lines. Three styles are available: \fBfull\fR, \fBtruncate\fR, and \fBwrap\fR. Setting \fIstyle\fR to \fBfull\fR will prevent cutting lines to \fBmax_report_width\fR; this is what occurs when \fBdetail\fR is 11 or higher. When \fIstyle\fR is \fBtruncate\fR (the default), long lines will be truncated according to \fBmax_report_width\fR. Setting \fIstyle\fR to \fBwrap\fR will wrap lines longer than \fBmax_report_width\fR such that left column hit counts are not obscured. This option takes precedence over the line style implied by the \fBdetail\fR level. The options \fB--full\fR, \fB--truncate\fR, and \fB--wrap\fR are synonyms. .IP "\fB--nodetail\fR" Disables the \fBDetailed\fR section of the report, and all supplemental reports. This option provides a convenient mechanism to quickly disable all sections under the \fBDetailed\fR report, where subsequent command line options may re-enable one or more sections to create specific reports. .PD 0 .IP "\fB--sarules \fR\`\fIS,H\fR\'" .IP "\fB--sarules default" .PD Enables the SpamAssassin Rules Hit report. The comma-separated \fIS\fR and \fIH\fR arguments are top N values for the Spam and Ham reports, respectively, and can be any integer greater than or equal to 0, or the keyword \fBall\fR. The keyword \fBdefault\fR uses the built-in default values. .IP "\fB--nosarules\fR" Disables the SpamAssassin Rules Hit report. .PD 0 .IP "\fB--sa_timings \fR\fInrows\fR" Enables the SpamAssassin Timings percentiles report. The report can be limited to the top N rows with the \fInrows\fR argument. This report requires Amavis 2.6+ and SpamAssassin 3.3+. .PD .IP "\fB--sa_timings_percentiles \fR\`\fIP1 [P2 ...]\fR\'" Specifies the percentiles shown in the SpamAssassin Timings report. The arguments \fIP1 ...\fR are integers from 0 to 100 inclusive. Their order will be preserved in the report. .IP "\fB--nosa_timings\fR" Disables the SpamAssassin Timings report. .IP "\fB--version\fR" Print \fBamavis-logwatch\fR version information. .PD 0 .IP "\fB--score_frequencies \fR\`\fIB1 [B2 ...]\fR\'" .IP "\fB--score_frequencies default" .PD Enables the Spam Score Frequency report. The arguments \fIB1 ...\fR are frequency distribution buckets, and can be any real numbers. Their order will be preserved in the report. The keyword \fBdefault\fR uses the built-in default values. .IP "\fB--noscore_frequencies\fR" Disables the Spam Score Frequency report. .PD 0 .IP "\fB--score_percentiles \fR\`\fIP1 [P2 ...]\fR\'" .IP "\fB--score_percentiles default" .PD Enables the Spam Score Percentiles report. The arguments \fIP1 ...\fR specify the percentiles shown in the report, and are integers from 0 to 100 inclusive. The keyword \fBdefault\fR uses the built-in default values. .IP "\fB--noscore_percentiles\fR" Disables the Spam Score Percentiles report. .IP "\fB--[no]sect_vars\fR" .PD 0 .IP "\fB--show_sect_vars \fIboolean\fR" .PD Enables (disables) supplementing each \fBDetailed\fR section title with the name of that section's level limiter. The name displayed is the command line option (or configuration file variable) used to limit that section's output. . With the large number of level limiters available in \fBamavis-logwatch\fR, this a convenient mechanism for determining exactly which level limiter affects a section. .IP "\fB--[no]startinfo\fR" .PD 0 .IP "\fB--show_startinfo \fIboolean\fR" .PD Enables (disables) the Amavis startup report showing most recent Amavis startup details. .IP "\fB--[no]summary\fR" .IP "\fB--show_summary\fR" Enables (disables) displaying of the the \fBSummary\fR section of the report. The variable Amavis_Show_Summary in used in a configuration file. .IP "\fB--syslog_name \fInamepat\fR" Specifies the syslog service name that \fBamavis-logwatch\fR uses to match syslog lines. Only log lines whose service name matches the perl regular expression \fInamepat\fR will be used by \fBamavis-logwatch\fR; all non-matching lines are silently ignored. This is useful when a pre-installed Amavis package uses a name other than the default (\fBamavis\fR). \fBNote:\fR if you use parenthesis in your regular expression, be sure they are cloistering and not capturing: use \fB(?:\fIpattern\fB)\fR instead of \fB(\fIpattern\fB)\fR. .PD 0 .IP "\fB--timings \fR\fIpercent\fR" Enables the Amavis Scan Timings percentiles report. The report can be top N-percent limited with the \fIpercent\fR argument. .PD .IP "\fB--timings_percentiles \fR\`\fIP1 [P2 ...]\fR\'" Specifies the percentiles shown in the Scan Timings report. The arguments \fIP1 ...\fR are integers from 0 to 100 inclusive. Their order will be preserved in the report. .IP "\fB--notimings\fR" Disables the Amavis Scan Timings report. .IP "\fB--version\fR" Print \fBamavis-logwatch\fR version information. .SS Level Limiters .PP The output of every section in the \fBDetailed\fR report is controlled by a level limiter. The name of the level limiter variable will be output when the \fBsect_vars\fR option is set. Level limiters are set either via command line in standalone mode with \fB--limit \fIlimiter\fB=\fIlevelspec\fR option, or via configuration file variable \fB$amavis_\fIlimiter\fB=\fIlevelspec\fR. Each limiter requires a \fIlevelspec\fR argument, which is described below in \fBLEVEL CONTROL\fR. The list of level limiters is shown below. .de TQ . br . ns . TP \\$1 .. .PD 0 .PP Amavis major contents category (ccatmajor) sections, listed in order of priority: VIRUS, BANNED, UNCHECKED, SPAM, SPAMMY, BADH, OVERSIZED, MTA, CLEAN. .IP "\fBMalwareBlocked" .IP "\fBMalwarePassed" Blocked or passed messages that contain malware (ccatmajor: VIRUS). .IP "\fBBannedNameBlocked" .IP "\fBBannedNamePassed" Blocked or passed messages that contain banned names in MIME parts (ccatmajor: BANNED). .IP "\fBUncheckedBlocked" .IP "\fBUncheckedPassed" Blocked or passed messages that were not checked by a virus scanner or SpamAssassin (Amavis ccatmajor: UNCHECKED). .IP "\fBSpamBlocked" .IP "\fBSpamPassed" Blocked or passed messages that were considered spam that reached kill level (Amavis ccatmajor: SPAM) .IP "\fBSpammyBlocked" .IP "\fBSpammyPassed" Blocked or passed messages that were considered spam, but did not reach kill level (Amavis ccatmajor: SPAMMY) .IP "\fBBadHeaderBlocked" .IP "\fBBadHeaderPassed" Blocked or passed messages that contain bad mail headers (ccatmajor: BAD-HEADER). .IP "\fBOversizedBlocked" .IP "\fBOversizedPassed" Blocked or passed messages that were considered oversized (Amavis ccatmajor: OVERSIZED). .IP "\fBMtaBlocked" .IP "\fBMtaPassed" Blocked or passed messages due to failure to re-inject to MTA (Amavis ccatmajor: MTA-BLOCKED). Occurrences of this event indicates a configuration problem. [ note: I don't believe mtapassed occurs, but exists for completeness.] .IP "\fBOtherBlocked" .IP "\fBOtherPassed" Blocked or passed messages that are not any of other major contents categories (Amavis ccatmajor: OTHER). .IP "\fBTempFailBlocked" .IP "\fBTempfailPassed" Blocked or passed messages that had a temporary failure (Amavis ccatmajor: TEMPFAIL) .IP "\fBCleanBlocked" .IP "\fBCleanPassed " Messages blocked or passed which were considered clean (Amavis ccatmajor: CLEAN; i.e. non-spam, non-viral). .PP Other sections, arranged alphabetically: .IP "\fBAvConnectFailure" Problems connecting to Anti-Virus scanner(s). .IP "\fBAvTimeout" Timeouts awaiting responses from Anti-Virus scanner(s). .IP "\fBArchiveExtract" Archive extraction problems. .IP "\fBBadHeaderSupp" Supplemental debug information regarding messages containing bad mail headers. .IP "\fBBayes" Messages frequencies by Bayesian probability buckets. .IP "\fBBadAddress" Invalid mail address syntax. .IP "\fBBlacklisted" Messages that were (soft-)blacklisted. See also Whitelisted below. .IP "\fBBounceKilled" .IP "\fBBounceRescued" .IP "\fBBounceUnverifiable" Disposition of incoming bounce messages (DSNs). .IP "\fBContentType" MIME attachment breakdown by type/subtype. .IP "\fBDccError" Errors encountered with or returned by DCC. .IP "\fBDefangError" Errors encountered during defang process. .IP "\fBDefanged" Messages defanged (rendered harmless). .IP "\fBDsnNotification" Errors encountered during attempt to send delivery status notification. .IP "\fBDsnSuppressed" Delivery status notification (DSN) intentionally suppressed. .IP "\fBExtraModules" Additional code modules Amavis loaded during runtime. .IP "\fBFakeSender" Forged sender addresses, as determined by Amavis. .IP "\fBFatal" Fatal events. These are presented at the top of the report, as they may require attention. .IP "\fBLocalDeliverySkipped" Failures delivering to a local address. .IP "\fBMalwareByScanner" Breakdown of malware by scanner(s) that detected the malware. .IP "\fBMimeError" Errors encountered during MIME extraction. .IP "\fBPanic" Panic events. These are presented at the top of the report, as they may require attention. .IP "\fBp0f" Passive fingerprint (p0f) hits, grouped by mail contents type (virus, unchecked, banned, spam, ham), next by operating system genre, and finally by IP address. Note: Windows systems are refined by Windows OS version, whereas versions of other operating systems are grouped generically. .IP "\fBReleased" Messages that were released from Amavis quarantine. .IP "\fBSADiags" Diagnostics as reported from SpamAssassin. .IP "\fBSmtpResponse" SMTP responses received during dialog with MTA. These log entries are primarly debug. .IP "\fBTmpPreserved" Temporary directories preserved by Amavis when some component encounters a problem or failure. Directories listed and their corresponding log entries should be evaluated for problems. .IP "\fBVirusScanSkipped" Messages that could not be scanned by a virus scanner. .IP "\fBWarning" Warning events not categorized in specific warnings below. These are presented at the top of the report, as they may require attention. .IP "\fBWarningAddressModified" Incomplete email addresses modified by Amavis for safety. .IP "\fBWarningNoQuarantineId" Attempts to release a quarantined message that did not contain an X-Quarantine-ID header. .IP "\fBWarningSecurity \fIlevelspec\fR" Insecure configuration or utility used by Amavis. .IP "\fBWarningSmtpShutdown" Failures during SMTP conversation with MTA. .IP "\fBWarningSql" Failures to communicate with, or error replies from, SQL service. .IP "\fBWhitelisted" Messages that were (soft-)whitelisted. See also Blacklisted above. .PD .SH LEVEL CONTROL .ad .fi The \fBDetailed\fR section of the report consists of a number of sub-sections, each of which is controlled both globally and independently. Two settings influence the output provided in the \fBDetailed\fR report: a global detail level (specified with \fB--detail\fR) which has final (big hammer) output-limiting control over the \fBDetailed\fR section, and sub-section specific detail settings (small hammer), which allow further limiting of the output for a sub-section. Each sub-section may be limited to a specific depth level, and each sub-level may be limited with top N or threshold limits. The \fIlevelspec\fR argument to each of the level limiters listed above is used to accomplish this. It is probably best to continue explanation of sub-level limiting with the following well-known outline-style hierarchy, and some basic examples: .nf level 0 level 1 level 2 level 3 level 4 level 4 level 2 level 3 level 4 level 4 level 4 level 3 level 4 level 3 level 1 level 2 level 3 level 4 .fi .PP The simplest form of output limiting suppresses all output below a specified level. For example, a \fIlevelspec\fR set to "2" shows only data in levels 0 through 2. Think of this as collapsing each sub-level 2 item, thus hiding all inferior levels (3, 4, ...), to yield: .nf level 0 level 1 level 2 level 2 level 1 level 2 .fi .PP Sometimes the volume of output in a section is too great, and it is useful to suppress any data that does not exceed a certain threshold value. Consider a dictionary spam attack, which produces very lengthy lists of hit-once recipient email or IP addresses. Each sub-level in the hierarchy can be threshold-limited by setting the \fIlevelspec\fR appropriately. Setting \fIlevelspec\fR to the value "2::5" will suppress any data at level 2 that does not exceed a hit count of 5. .PP Perhaps producing a top N list, such as top 10 senders, is desired. A \fIlevelspec\fR of "3:10:" limits level 3 data to only the top 10 hits. .PP With those simple examples out of the way, a \fIlevelspec\fR is defined as a whitespace- or comma-separated list of one or more of the following: .IP "\fIl\fR" Specifies the maximum level to be output for this sub-section, with a range from 0 to 10. if \fIl\fR is 0, no levels will be output, effectively disabling the sub-section (level 0 data is already provided in the Summary report, so level 1 is considered the first useful level in the \fBDetailed\fR report). Higher values will produce output up to and including the specified level. .IP "\fIl\fB.\fIn\fR" Same as above, with the addition that \fIn\fR limits this section's level 1 output to the top \fIn\fR items. The value for \fIn\fR can be any integer greater than 1. (This form of limiting has less utility than the syntax shown below. It is provided for backwards compatibility; users are encouraged to use the syntax below). .IP "\fIl\fB:\fIn\fB:\fIt\fR" This triplet specifies level \fIl\fR, top \fIn\fR, and minimum threshold \fIt\fR. Each of the values are integers, with \fIl\fR being the level limiter as described above, \fIn\fR being a top \fIn\fR limiter for the level \fIl\fR, and \fIt\fR being the threshold limiter for level \fIl\fR. When both \fIn\fR and \fIt\fR are specified, \fIn\fR has priority, allowing top \fIn\fR lists (regardless of threshold value). If the value of \fIl\fR is omitted, the specified values for \fIn\fR and/or \fIt\fR are used for all levels available in the sub-section. This permits a simple form of wildcarding (eg. place minimum threshold limits on all levels). However, specific limiters always override wildcard limiters. The first form of level limiter may be included in \fIlevelspec\fR to restrict output, regardless of how many triplets are present. .PP All three forms of limiters are effective only when \fBamavis-logwatch\fR's detail level is 5 or greater (the \fBDetailed\fR section is not activated until detail is at least 5). .PP See the \fBEXAMPLES\fR section for usage scenarios. .SH CONFIGURATION FILE .ad \fBAmavis-logwatch\fR can read configuration settings from a configuration file. Essentially, any command line option can be placed into a configuration file, and these settings are read upon startup. Because \fBamavis-logwatch\fR can run either standalone or within Logwatch, to minimize confusion, \fBamavis-logwatch\fR inherits Logwatch's configuration file syntax requirements and conventions. These are: .IP \(bu 4'. White space lines are ignored. .IP \(bu 4'. Lines beginning with \fB#\fR are ignored .IP \(bu 4'. Settings are of the form: .nf \fIoption\fB = \fIvalue\fR .fi .IP \(bu 4'. Spaces or tabs on either side of the \fB=\fR character are ignored. .IP \(bu 4'. Any \fIvalue\fR protected in double quotes will be case-preserved. .IP \(bu 4'. All other content is reduced to lowercase (non-preserving, case insensitive). .IP \(bu 4'. All \fBamavis-logwatch\fR configuration settings must be prefixed with "\fB$amavis_\fR" or \fBamavis-logwatch\fR will ignore them. .IP \(bu 4'. When running under Logwatch, any values not prefixed with "\fB$amavis_\fR" are consumed by Logwatch; it only passes to \fBamavis-logwatch\fR (via environment variable) settings it considers valid. .IP \(bu 4'. The values \fBTrue\fR and \fBYes\fR are converted to 1, and \fBFalse\fR and \fBNo\fR are converted to 0. .IP \(bu 4'. Order of settings is not preserved within a configuration file (since settings are passed by Logwatch via environment variables, which have no defined order). .PP To include a command line option in a configuration file, prefix the command line option name with the word "\fB$amavis_\fR". The following configuration file setting and command line option are equivalent: .nf \fB$amavis_Line_Style = Truncate\fR \fB--line_style Truncate\fR .fi Level limiters are also prefixed with \fB$amavis_\fR, but on the command line are specified with the \fB--limit\fR option: .nf \fB$amavis_SpamBlocked = 2\fR \fB--limit SpamBlocked=2\fR .fi The order of command line options and configuration file processing occurs as follows: 1) The default configuration file is read if it exists and no \fB--config_file\fR was specified on a command line. 2) Configuration files are read and processed in the order found on the command line. 3) Command line options override any options already set either via command line or from any configuration file. Command line options are interpreted when they are seen on the command line, and later options will override previously set options. .SH "EXIT STATUS" .na .nf .ad .fi The \fBamavis-logwatch\fR utility exits with a status code of 0, unless an error occurred, in which case a non-zero exit status is returned. .SH "EXAMPLES" .na .nf .ad .fi .SS Running Standalone \fBNote:\fR \fBamavis-logwatch\fR reads its log data from one or more named Amavis log files, or from STDIN. For brevity, where required, the examples below use the word \fIfile\fR as the command line argument meaning \fI/path/to/amavis.log\fR. Obviously you will need to substitute \fIfile\fR with the appropriate path. .nf .PP To run \fBamavis-logwatch\fR in standalone mode, simply run: .nf .RS 4 .PP \fBamavis-logwatch \fIfile\fR .RE 0 .nf .PP A complete list of options and basic usage is available via: .nf .RS 4 .PP \fBamavis-logwatch --help\fR .RE 0 .nf .PP To print a summary only report of Amavis log data: .nf .RS 4 .PP \fBamavis-logwatch --detail 1 \fIfile\fR .RE 0 .fi .PP To produce a summary report and a one-level detail report for May 25th: .nf .RS 4 .PP \fBgrep 'May 25' \fIfile\fB | amavis-logwatch --detail 5\fR .RE 0 .fi .PP To produce only a top 10 list of Sent email domains, the summary report and detailed reports are first disabled. Since commands line options are read and enabled left-to-right, the Sent section is re-enabled to level 1 with a level 1 top 10 limiter: .nf .RS 4 .PP \fBamavis-logwatch --nosummary --nodetail \\ --limit spamblocked '1 1:10:' \fIfile\fR .RE 0 .fi .PP The following command and its sample output shows a more complex level limiter example. The command gives the top 4 spam blocked recipients (level 1), and under with each recipient the top 2 sending IPs (level 2) and finally below that, only envelope from addresses (level 3) with hit counts greater than 6. Ellipses indicate top N or threshold-limited data: .nf .RS 4 .PP \fBamavis-logwatch --nosummary --nodetail \\ --limit spamblocked '1:4: 2:2: 3::6' \fIfile\fR .nf 19346 Spam blocked ----------------------------------- 756 joe@example.com 12 10.0.0.1 12 <> 12 10.99.99.99 12 <> ... 640 fred@example.com 8 10.0.0.1 8 <> 8 192.168.3.19 8 <> ... 595 peter@sample.net 8 10.0.0.1 8 <> 7 192.168.3.3 7 <> ... 547 paul@example.us 8 192.168.3.19 8 <> 7 10.0.0.1 7 <> ... ... .fi .RE 0 .fi .SS Running within Logwatch \fBNote:\fR Logwatch versions prior to 7.3.6, unless configured otherwise, required the \fB--print\fR option to print to STDOUT instead of sending reports via email. Since version 7.3.6, STDOUT is the default output destination, and the \fB--print\fR option has been replaced by \fB--output stdout\fR. Check your configuration to determine where report output will be directed, and add the appropriate option to the commands below. .PP To print a summary report for today's Amavis log data: .nf .RS 4 .PP \fBlogwatch --service amavis --range today --detail 1\fR .RE 0 .nf .PP To print a report for today's Amavis log data, with one level of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service amavis --range today --detail 5\fR .RE 0 .fi .PP To print a report for yesterday, with two levels of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service amavis --range yesterday --detail 6\fR .RE 0 .fi .PP To print a report from Dec 12th through Dec 14th, with four levels of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service amavis --range \\ 'between 12/12 and 12/14' --detail 8\fR .RE 0 .PP To print a report for today, with all levels of detail: .nf .RS 4 .PP \fBlogwatch --service amavis --range today --detail 10\fR .RE 0 .PP Same as above, but leaves long lines uncropped: .nf .RS 4 .PP \fBlogwatch --service amavis --range today --detail 11\fR .RE 0 .SS "Amavis Log Level" .PP Amavis provides additional log information when the variable \fB$log_level\fR is increased above the default 0 value. This information is used by the \fBamavis-logwatch\fR utility to provide additional reports, not available with the default \fB$log_level\fR=0 value. A \fB$log_level\fR of 2 is suggested. .PP If you prefer not to increase the noise level in your main mail or Amavis logs, you can configure syslog to log Amavis' output to multiple log files, where basic log entries are routed to your main mail log(s) and more detailed entries routed to an Amavis-specific log file used to feed the \fBamavis-logwatch\fR utility. .PP A convenient way to accomplish this is to change the Amavis configuration variables in \fBamavisd.conf\fR as shown below: .nf amavisd.conf: $log_level = 2; $syslog_facility = 'local5'; $syslog_priority = 'debug'; .fi .PP This increases \fB$log_level\fR to 2, and sends Amavis' log entries to an alternate syslog facility (eg. \fBlocal5\fR, user), which can then be routed to one or more log files, including your main mail log file: .nf syslog.conf: #mail.info -/var/log/maillog mail.info;local5.notice -/var/log/maillog local5.info -/var/log/amavisd-info.log .fi .PP \fBAmavis\fR' typical \fB$log_level\fR 0 messages will be directed to both your maillog and to the \fBamavisd-info.log\fR file, but higher \fB$log_level\fR messages will only be routed to the \fBamavisd-info.log\fR file. For additional information on Amavis' logging, search the file \fBRELEASE_NOTES\fR in the Amavis distribution for: .nf "syslog priorities are now dynamically derived" .fi .SH "ENVIRONMENT" .na .nf .ad .fi The \fBamavis-logwatch\fR program uses the following (automatically set) environment variables when running under Logwatch: .IP \fBLOGWATCH_DETAIL_LEVEL\fR This is the detail level specified with the Logwatch command line argument \fB--detail\fR or the \fBDetail\fR setting in the ...conf/services/amavis.conf configuration file. .IP \fBLOGWATCH_DEBUG\fR This is the debug level specified with the Logwatch command line argument \fB--debug\fR. .IP \fBamavis_\fIxxx\fR The Logwatch program passes all settings \fBamavis_\fIxxx\fR in the configuration file ...conf/services/amavis.conf to the \fBamavis\fR filter (which is actually named .../scripts/services/amavis) via environment variable. .SH "FILES" .na .nf .SS Standalone mode .IP "/usr/local/bin/amavis-logwatch" The \fBamavis-logwatch\fR program .IP "/usr/local/etc/amavis-logwatch.conf" The \fBamavis-logwatch\fR configuration file in standalone mode .SS Logwatch mode .IP "/etc/logwatch/scripts/services/amavis" The Logwatch \fBamavis\fR filter .IP "/etc/logwatch/conf/services/amavis.conf" The Logwatch \fBamavis\fR filter configuration file .SH "SEE ALSO" .na .nf logwatch(8), system log analyzer and reporter .SH "README FILES" .na .ad .nf README, an overview of \fBamavis-logwatch\fR Changes, the version change list history Bugs, a list of the current bugs or other inadequacies Makefile, the rudimentary installer LICENSE, the usage and redistribution licensing terms .SH "LICENSE" .na .nf .ad Covered under the included MIT/X-Consortium License: http://www.opensource.org/licenses/mit-license.php .SH "AUTHOR(S)" .na .nf Mike Cappella .fi The original \fBamavis\fR Logwatch filter was written by Jim O'Halloran, and has had many contributors over the years. They are entirely not responsible for any errors, problems or failures since the current author's hands have touched the source code. logwatch-7.7/install_logwatch.sh0000664000211400021140000002630513555413754017305 0ustar logwatchlogwatch#!/bin/sh # #The MIT License # #Copyright (c) 2005-2006 Mike Tremaine # #Permission is hereby granted, free of charge, to any person obtaining #a copy of this software and associated documentation files (the "Software"), #to deal in the Software without restriction, including without limitation #the rights to use, copy, modify, merge, publish, distribute, sublicense, #and/or sell copies of the Software, and to permit persons to whom the #Software is furnished to do so, subject to the following conditions: # #The above copyright notice and this permission notice shall be included #in all copies or substantial portions of the Software. # #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF #MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. #IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, #DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR #OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR #THE USE OR OTHER DEALINGS IN THE SOFTWARE. # __________________________________________________________________ # # File: install_logwatch.sh # Author: Mike Tremaine [mgt /at/ stellarcore.net] # Maintainer: Mike Tremaine [mgt /at/ stellarcore.net] # $Id$ # # $Log: install_logwatch.sh,v $ # Revision 1.20 2008/05/12 22:53:28 mike # removed -T flag no sure why it was there -mgt # # Revision 1.19 2008/05/08 23:15:55 mike # Added install to logwatch.cron if no cron.daily dir. -mgt # # Revision 1.18 2008/05/08 22:47:41 mike # Added BIGGER note for the new cron requirement -mgt # # Revision 1.17 2007/11/28 16:06:56 mike # Prefix option code from Craig Ruff -mgt # # Revision 1.16 2007/11/28 15:50:43 mike # Typod Craig Ruff sorry -mgt # # Revision 1.15 2007/11/28 15:49:47 mike # Patch from Craig Ruff for MANDIR under Solaris -mgt # # Revision 1.14 2007/11/28 15:43:14 mike # Patch from Craig Ruff for CONFIGDIR munge -mgt # # __________________________________________________________________ # #Note: This script is provided for the non-RPM installs. #It is preferred that logwatch be packaged by a distribution #specifically for your installation. But since that is not always #possible we have included this script. #Add PATHS for various OS options #Set PATH for solaris /usr/ucb/install PATH=/usr/ucb:$PATH #Set PATH for OpenBSD makewhatis /usr/libexec/makewhatis PATH=$PATH:/usr/libexec #Set PATH for IRIX makewhatis /usr/lib/makewhatis PATH=$PATH:/usr/lib export PATH #Set OS and GLOBIGNORE OS=`uname -s` GLOBIGNORE=*CVS #All these can be set via user input #Defaults BASEDIR="/usr/share/logwatch" CONFIGDIR="/etc/logwatch" TEMPDIR="/var/cache/logwatch" PERLEXE="/usr/bin/perl" MANDIR="/usr/share/man" #Command line options section ac_prev= systemd=0 for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` case $ac_option in -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; --systemd) systemd=1;; *) echo "Unknown option '$ac_option'" echo "Valid options are --prefix and --systemd." echo " Option --prefix takes one argument: a path name, which will" echo " be prepended to installation directory names" echo " Option --systemd installs the systemd files logwatch.service" echo " and logwatch.timer rather than the default 0logwatch" echo " file in /etc/cron.daily/" exit ;; esac done if [ "x$prefix" != "x" ]; then BASEDIR=$prefix munge_base=1 CONFIGDIR=$BASEDIR/etc munge_conf=1 TEMPDIR=$BASEDIR/tmp munge_temp=1 MANDIR=$BASEDIR/man fi #Talk to user printf "#################################\n" printf "Preparing to install Logwatch\n" printf "Enter the path to the Logwatch BaseDir [$BASEDIR] : " read base if [ "$base" = "" ]; then printf "### Using $BASEDIR\n" else BASEDIR="$base" #Set munge flag munge_base=1 printf "### Using $BASEDIR [will modify logwatch.pl]\n" fi printf "Enter the path for the Logwatch ConfigDir [$CONFIGDIR] : " read config if [ "$config" = "" ]; then printf "### Using $CONFIGDIR\n" else CONFIGDIR="$config" munge_conf=1 printf "### Using $CONFIGDIR [will modify logwatch.pl]\n" fi printf "Enter the dir name to be used for temp files [$TEMPDIR] : " read temp if [ "$temp" = "" ]; then printf "### Using $TEMPDIR\n" else TEMPDIR="$temp" munge_temp=1 printf "### Using $TEMPDIR [will write to $CONFIGDIR/conf/logwatch.conf]\n" fi printf "Enter the location of perl [$PERLEXE] : " read perlexe if [ "$perlexe" = "" ]; then printf "### Using $PERLEXE\n" else PERLEXE="$perlexe" munge_perl=1 printf "### Using $PERLEXE [will modify logwatch.pl]\n" fi printf "Enter the dir name to used for the manpage [$MANDIR] : " read mandir if [ "$mandir" = "" ]; then printf "### Using $MANDIR\n" else MANDIR="$mandir" printf "### Using $MANDIR [Will try to run makewhatis]\n" fi echo "### Installing" #OS Tests for known issues if [ $OS = "Darwin" ]; then munge_gzcat=1 fi #Install is borked under IRIX #BASE install -m 0755 -d $BASEDIR install -m 0755 -d $BASEDIR/dist.conf install -m 0755 -d $BASEDIR/dist.conf/logfiles install -m 0755 -d $BASEDIR/dist.conf/services install -m 0755 -d $BASEDIR/default.conf install -m 0755 -d $BASEDIR/default.conf/logfiles install -m 0755 -d $BASEDIR/default.conf/services install -m 0755 -d $BASEDIR/default.conf/html install -m 0755 -d $BASEDIR/scripts install -m 0755 -d $BASEDIR/scripts/logfiles install -m 0755 -d $BASEDIR/scripts/services install -m 0755 -d $BASEDIR/scripts/shared install -m 0755 -d $BASEDIR/lib install -m 0644 README $BASEDIR/README install -m 0644 HOWTO-Customize-LogWatch $BASEDIR/HOWTO-Customize-LogWatch install -m 0644 conf/*.conf $BASEDIR/default.conf install -m 0644 conf/logfiles/* $BASEDIR/default.conf/logfiles install -m 0644 conf/services/* $BASEDIR/default.conf/services install -m 0644 conf/html/* $BASEDIR/default.conf/html install -m 0755 scripts/logwatch.pl $BASEDIR/scripts/logwatch.pl for i in scripts/logfiles/* ; do if [ `ls $i | grep -v CVS | wc -l` -ne 0 ] ; then install -m 0755 -d $BASEDIR/$i install -m 0644 $i/* $BASEDIR/$i fi done install -m 0644 scripts/shared/* $BASEDIR/scripts/shared install -m 0644 scripts/services/* $BASEDIR/scripts/services install -m 0644 lib/* $BASEDIR/lib if [ $munge_base ]; then perl -pi -e "s%/usr/share/logwatch%$BASEDIR%" $BASEDIR/scripts/logwatch.pl fi #CONFIG install -m 0755 -d $CONFIGDIR install -m 0755 -d $CONFIGDIR/scripts install -m 0755 -d $CONFIGDIR/scripts/services install -m 0755 -d $CONFIGDIR/conf install -m 0755 -d $CONFIGDIR/conf/logfiles install -m 0755 -d $CONFIGDIR/conf/services install -m 0755 -d $CONFIGDIR/conf/html if [ $munge_conf ]; then perl -pi -e "s%/etc/logwatch%$CONFIGDIR%" $BASEDIR/scripts/logwatch.pl fi touch $CONFIGDIR/conf/logwatch.conf touch $CONFIGDIR/conf/ignore.conf touch $CONFIGDIR/conf/override.conf #TEMP #Using sanity check incase someone uses /tmp. #The install would destroy the perms on /tmp if [ ! -d $TEMPDIR ]; then #Should this be 0700 -d $TEMPDIR ?? install -m 0755 -d $TEMPDIR fi #This can create duplicates need to grep first -mgt if [ $munge_temp ]; then echo "TmpDir = $TEMPDIR" >> $CONFIGDIR/conf/logwatch.conf fi #PERL if [ $munge_perl ]; then perl -pi -e "s%/usr/bin/perl%$PERLEXE%" $BASEDIR/scripts/logwatch.pl fi #Gzcat if [ $munge_gzcat ]; then echo "Pathtozcat = gzcat" >> $CONFIGDIR/conf/logwatch.conf fi #Search for makewhatis for f in `echo $PATH | tr : ' '`; do if [ -x "$f/makewhatis" ]; then HAVE_MAKEWHATIS=1; fi; done #Man page if [ -d $MANDIR/man5 ] && [ -d $MANDIR/man8 ] && [ -d $MANDIR/man1 ] && [ $HAVE_MAKEWHATIS ]; then install -m 0644 logwatch.8 $MANDIR/man8 install -m 0644 logwatch.conf.5 $MANDIR/man5 ln -sf $MANDIR/man5/logwatch.conf.5 $MANDIR/man5/ignore.conf.5 ln -sf $MANDIR/man5/logwatch.conf.5 $MANDIR/man5/override.conf.5 install -m 0644 postfix-logwatch.1 $MANDIR/man1 install -m 0644 amavis-logwatch.1 $MANDIR/man1 #OpenBSD no -s if [ $OS = "OpenBSD" ]; then makewhatis -u $MANDIR/man5 $MANDIR/man8 $MANDIR/man1 else #FreeBSD and NetBSD no -s no -u if [ $OS = "FreeBSD" ] || [ $OS = "NetBSD" ]; then makewhatis $MANDIR/man5 $MANDIR/man8 $MANDIR/man1 else #MacOS X aka Darwin no -u [even thought the manpage says] if [ $OS = "Darwin" ]; then makewhatis -o "1 5 8" $MANDIR else #Linux makewhatis -u -s "1 5 8" $MANDIR fi fi fi else if [ $OS = "SunOS" ]; then #Go for the safe install rather than editing man.cf mkdir -p $MANDIR/man1m > /dev/null 2>&1 install -m 0644 logwatch.8 $MANDIR/man1m install -m 0644 logwatch.conf.5 $MANDIR/man1m ln -sf $MANDIR/man1m/logwatch.conf.5 $MANDIR/man1m/ignore.conf.5 ln -sf $MANDIR/man1m/logwatch.conf.5 $MANDIR/man1m/override.conf.5 install -m 0644 postfix-logwatch.1 $MANDIR/man1 install -m 0644 amavis-logwatch.1 $MANDIR/man1 catman -w -M $MANDIR/man1m else install -m 0755 -d $MANDIR/man1 install -m 0644 postfix-logwatch.1 $MANDIR/man1 install -m 0644 amavis-logwatch.1 $MANDIR/man1 install -m 0755 -d $MANDIR/man5 install -m 0644 logwatch.conf.5 $MANDIR/man5 ln -sf $MANDIR/man5/logwatch.conf.5 $MANDIR/man5/ignore.conf.5 ln -sf $MANDIR/man5/logwatch.conf.5 $MANDIR/man5/override.conf.5 install -m 0755 -d $MANDIR/man8 install -m 0644 logwatch.8 $MANDIR/man8 printf "Installed manpages in $MANDIR/man1, $MANDIR/man5 and $MANDIR/man8.\n" printf "Check your man.cf or man.conf to enable MANSECTS 1, 5 and 8\n" fi fi #Symlink ln -f -s $BASEDIR/scripts/logwatch.pl /usr/sbin/logwatch printf "Created symlink for /usr/sbin/logwatch \n" #Cron or Systemd timer if [ $systemd -eq 1 ]; then install -m 0644 scheduler/logwatch.service /lib/systemd/system/logwatch.service install -m 0644 scheduler/logwatch.timer /lib/systemd/system/logwatch.timer install -m 0644 scheduler/systemd.conf $BASEDIR/default.conf/systemd.conf if [ ! -e /lib/systemd/system/multi-user.target.wants ]; then install -m 0755 -d /lib/systemd/system/multi-user.target.wants fi ln -sf ../logwatch.timer /lib/systemd/system/multi-user.target.wants/logwatch.timer printf "Created and enabled systemd logwatch.timer" elif [ -d /etc/cron.daily ]; then rm -f /etc/cron.daily/0logwatch install -m 0755 scheduler/logwatch.cron /etc/cron.daily/0logwatch printf "Created /etc/cron.daily/0logwatch \n" else install -m 0744 scheduler/logwatch.cron $CONFIGDIR/logwatch.cron printf "################ README ####################.\n" printf "You need to setup your cron job for logwatch.\n" printf "A sample script is included see $CONFIGDIR/logwatch.cron. \n" printf "2 0 * * * $CONFIGDIR/logwatch.cron >/dev/null 2>&1 \n" fi exit # vi: shiftwidth=3 tabstop=3 et logwatch-7.7/ignore.conf.50000664000211400021140000000003012670102056015656 0ustar logwatchlogwatch.so man5/logwatch.conf.5logwatch-7.7/lib/0000775000211400021140000000000014200067336014140 5ustar logwatchlogwatchlogwatch-7.7/lib/Logwatch.pm0000664000211400021140000004307514200067336016257 0ustar logwatchlogwatch#!/usr/bin/perl # # $Id$ package Logwatch; use strict; use Exporter; use POSIX qw(strftime); =pod =head1 NAME Logwatch -- Utility functions for Logwatch Perl modules. =head1 SYNOPSIS use Logwatch ':sort'; ## ## Show CountOrder() ## # Sample Data my %UnknownUsers = (jb1o => 4, eo00 => 1, ma3d => 4, dr4b => 1); my $sortClosure = CountOrder(%UnknownUsers); foreach my $user (sort $sortClosure keys %UnknownUsers) { my $plural = ($UnknownUsers{$user} > 1) ? "s" : ""; printf " %-8s : %2d time%s\n", $user, $UnknownUsers{$user}, $plural; } ## ## Show TotalCountOrder() ## # Sample Data my %RelayDenied = ( some.server => {you@some.where => 2, foo@bar.com => 4}, other.server => { foo@bar.com => 14 } ); my $sub = TotalCountOrder(%RelayDenied); foreach my $relay (sort $sub keys %RelayDenied) { print " $relay:\n"; my $countOrder = CountOrder(%{$RelayDenied{$relay}}); foreach my $dest (sort $countOrder keys %{$RelayDenied{$relay}}) { my $plural = ($RelayDenied{$relay}{$dest} > 1) ? "s" : ""; printf " %-36s: %3d Time%s\n", $dest, $RelayDenied{$relay}{$dest}, $plural; } } use Logwatch ':ip'; ## ## Show SortIP() ## # Sample Data @ReverseFailures = qw{10.1.1.1 172.16.1.1 10.2.2.2 192.168.1.1 }; @ReverseFailures = sort SortIP @ReverseFailures; { local $" = "\n "; print "Reverse DNS Failures:\n @ReverseFailures\n" } -or- ## ## Show LookupIP() ## foreach my $ip (sort SortIP @ReverseFailures) { printf "%15s : %s\n", $ip, LookupIP($ip); } =head1 DESCRIPTION This module provides utility functions intended for authors of Logwatch scripts. The purpose is to abstract commonly performed actions into a set of generally available subroutines. The subroutines can optionally be imported into the local namespace. =over 4 =cut our @ISA = qw{Exporter}; our @EXPORT; our @EXPORT_OK; our %EXPORT_TAGS = (sort => [qw(CountOrder TotalCountOrder SortIP)], ip => [qw(DoLookup LookupIP SortIP)], dates => [qw(RangeHelpDM GetPeriod TimeBuild TimeFilter)], ); Exporter::export_ok_tags(qw{sort ip dates}); $EXPORT_TAGS{all} = [@EXPORT, @EXPORT_OK]; =pod =item I This function returns a closure suitable to be passed to Perl's C builtin. When two values are passed to the closure, it compares the numeric values of those keys in C<%hash>, and if they're equal, the lexically order of the keys. Thus: my $sortClosure = CountOrder(%UnknownUsers); foreach my $user (sort $sortClosure keys %UnknownUsers) { my $plural = ($UnknownUsers{$user} > 1) ? "s" : ""; printf " %-8s : %2d time%s\n", $user, $UnknownUsers{$user}, $plural; } Will print the keys and values of C<%UnknownUsers> in frequency order, with keys of equal values sorted lexically. The optional second argument is a coderef to be used to sort the keys in an order other than lexically. (a reference to C, for example.) =cut # Use a closure to abstract the sort algorithm sub CountOrder(\%;&) { my $href = shift; my $coderef = shift; return sub { # $a & $b are in the caller's namespace, moving this inside # guarantees that the namespace of the sort is used, in case # it's different (admittedly, that's highly unlikely), at a # miniscule performance cost. my $package = (caller)[0]; no strict 'refs'; # Back off, man. I'm a scientist. my $A = $ {"${package}::a"}; my $B = $ {"${package}::b"}; use strict 'refs'; # We are a hedge. Please move along. # Reverse the count, but not the compare my $count = $href->{$B} <=> $href->{$A}; return $count if $count; if (ref $coderef) { $a = $A; $b = $B; &$coderef(); } else { ($A cmp $B); } } } =pod =item I This function returns a closure similar to that returned by C, except that it assumes a hash of hashes, and totals the keys of each sub hash. Thus: my $sub = TotalCountOrder(%RelayDenied); foreach my $relay (sort $sub keys %RelayDenied) { print " $relay:\n"; my $countOrder = CountOrder(%{$RelayDenied{$relay}}); foreach my $dest (sort $countOrder keys %{$RelayDenied{$relay}}) { my $plural = ($RelayDenied{$relay}{$dest} > 1) ? "s" : ""; printf " %-36s: %3d Time%s\n", $dest, $RelayDenied{$relay}{$dest}, $plural; } } Will print the relays in the order of their total denied destinations (equal keys sort lexically), with each sub hash printed in frequency order (equal keys sorted lexically) The optional second argument is a coderef to be used to sort the keys in an order other than lexically. (a reference to C, for example.) =cut sub TotalCountOrder(\%;&) { my $href = shift; my $coderef = shift; my $cache = {}; return sub { # $a & $b are in the caller's namespace, moving this inside # guarantees that the namespace of the sort is used, in case # it's different (admittedly, that's highly unlikely), at a # miniscule performance cost. my $package = (caller)[0]; no strict 'refs'; # Back off, man. I'm a scientist. my $A = $ {"${package}::a"}; my $B = $ {"${package}::b"}; use strict 'refs'; # We are a hedge. Please move along. my ($AA, $BB); foreach my $tuple ( [\$A, \$AA], [\$B, \$BB] ) { my $keyRef = $tuple->[0]; my $totalRef = $tuple->[1]; if (exists($cache->{$$keyRef})) { $$totalRef = $cache->{$$keyRef}; } else { grep {$$totalRef += $href->{$$keyRef}->{$_}} keys %{$href->{$$keyRef}}; $cache->{$$keyRef} = $$totalRef; } } my $count = $BB <=> $AA; return $count if $count; if (ref $coderef) { $a = $A; $b = $B; &$coderef(); } else { ($A cmp $B); } } } =pod =item I This function is meant to be passed to the perl C builtin. It sorts a list of "dotted quad" IP addresses by the values of the individual octets. =cut sub canonical_ipv6_address { my @a = split /:/, shift; my @b = qw(0 0 0 0 0 0 0 0); my $i = 0; # comparison is numeric, so we use hex function while (defined $a[0] and $a[0] ne '') {$b[$i++] = hex(shift @a);} @a = reverse @a; $i = 7; while (defined $a[0] and $a[0] ne '') {$b[$i--] = hex(shift @a);} @b; } sub SortIP { # $a & $b are in the caller's namespace. my $package = (caller)[0]; no strict 'refs'; # Back off, man. I'm a scientist. my $A = $ {"${package}::a"}; my $B = $ {"${package}::b"}; $A =~ s/^::(ffff:)?(\d+\.\d+\.\d+\.\d+)$/$2/; $B =~ s/^::(ffff:)?(\d+\.\d+\.\d+\.\d+)$/$2/; use strict 'refs'; # We are a hedge. Please move along. if ($A =~ /:/ and $B =~ /:/) { my @a = canonical_ipv6_address($A); my @b = canonical_ipv6_address($B); while ($a[1] and $a[0] == $b[0]) {shift @a; shift @b;} $a[0] <=> $b[0]; } elsif ($A =~ /:/) { -1; } elsif ($B =~ /:/) { 1; } else { my ($a1, $a2, $a3, $a4) = split /\./, $A; my ($b1, $b2, $b3, $b4) = split /\./, $B; $a1 <=> $b1 || $a2 <=> $b2 || $a3 <=> $b3 || $a4 <=> $b4; } } =pod =item I Sets whether C does hostname lookups (or not). Defaults to true. =item I This function performs a hostname lookup on a passed in IP address. It returns the IP (with the hostname in parentheses) on success and the IP address on failure. Results are cached, so that many calls with the same argument don't tax the resolver resources. For (new) backward compatibility, this function now uses the $DoLookup variable in the caller's namespace to determine if lookups will be made. =cut # Default to false my $DoLookup = 0; sub DoLookup { $DoLookup = shift; return; } # Might as well cache it for the duration of the run my %LookupCache = (); sub LookupIP { my $Addr = $_[0]; if ($ENV{'LOGWATCH_NUMERIC'} == 1 ) { return $Addr; } # "Socket" is used solely to get the AF_INET() and AF_INET6() # constants, usually 2 and 10, respectively. Using Socket is # preferred because of portability, and should be in the standard # Perl distribution. eval "use Socket"; my $hasSocket = $@? 0 : 1; return $Addr unless($DoLookup && $hasSocket); return $LookupCache{$Addr} if exists ($LookupCache{$Addr}); $Addr =~ s/^::ffff://; my $PackedAddr; my $name = ""; # there are other module functions that do this more gracefully # (such as inet_pton), but we can't guarantee that they are available # in every system, so we use the built-in gethostbyaddr. if ($Addr =~ /^[\d\.]*$/) { $PackedAddr = pack('C4', split /\./,$Addr); $name = gethostbyaddr($PackedAddr,AF_INET()); } elsif ($Addr =~ /^[0-9a-zA-Z:]*/) { $PackedAddr = pack('n8', canonical_ipv6_address($Addr)); $name = gethostbyaddr($PackedAddr, AF_INET6()); } if ($name) { my $val = "$Addr ($name)"; $LookupCache{$Addr} = $val; return $val; } else { $LookupCache{$Addr} = $Addr; return ($Addr); } } =pod =item I This function merely prints out some information about --range to STDERR. =cut sub RangeHelpDM { eval "use Date::Manip"; my $hasDM = $@ ? 0 : 1; if ($hasDM) { print STDERR "\nThis system has the Date::Manip module loaded, and therefore you may use all\n"; print STDERR "of the valid --range parameters.\n"; } else { print STDERR "\nThis system does not have Date::Manip module loaded, and therefore\n"; print STDERR "the only valid --range parameters are \"yesterday\", \"today\", or \"all\".\n"; print STDERR "The Date::Manip module can be installed by using either of:\n"; print STDERR " apt-get install libdate-manip-perl (recommended on Debian)'\n"; print STDERR " cpan -i 'Date::Manip'\n"; print STDERR " perl -MCPAN -e 'install Date::Manip'\n"; print STDERR "\nFollowing is a description of the full capabilities available if\n"; print STDERR "Date::Manip is available.\n"; } print STDERR <<"EOT"; The format of the range option is: --range \"date_range [period]\" Parameter date_range (and optional period) must be enclosed in double quotes if it is more than one word. The default for date_range is \"yesterday\". Valid instances of date_range have one of the following formats: yesterday today all date1 between date1 and date2 since date1 For the above, date1 and date2 have values that can be parsed with the Date::Manip perl module. Valid instances of the optional parameter period have one of the following formats: for (that|this) (year|month|day|hour|minute|second) for those (years|months|days|hours|minutes|seconds) The period defines the resolution of the date match. The default is \"for that day\". Examples: --range today --range yesterday --range \"4 hours ago for that hour\" --range \"-3 days\" --range \"since 2 hours ago for those hours\" --range \"between -10 days and -2 days\" --range \"Apr 15, 2005\" --range \"first Monday in May\" --range \"between 4/23/2005 and 4/30/2005\" --range \"2005/05/03 10:24:17 for that second\" (The last entry might be used by someone debugging a log or filter.) A caution about efficiency: a range of \"yesterday for those hours\" will search for log entries for the last 24 hours, and is inefficient because it searches for individual matches for each hour. A range of \"yesterday\" will search for log entries for the previous day, and it searches for a single date match. EOT ; } =pod =item I This function returns the period, which is the part after the "for (those|that|this) " in a range =cut sub GetPeriod { my $range = lc $ENV{"LOGWATCH_DATE_RANGE"} || "yesterday"; my ($period) = ($range =~ /for\s+(?:those|that|this)\s+(year|month|day|hour|minute|second)s?\s*$/); if ($range eq 'all') { $period = 'all'; } unless ($period) { $period = "day"; } return($period); } =pod =item I This function returns an array of integers denoting time since the epoch (Jan. 1, 1970). Each entry represents a timestamp for the period that will that will need to be looked up to create the filter. =cut sub TimeBuild { my @time_t; my $time = time; eval "use Date::Manip"; my $hasDM = $@ ? 0 : 1; if ($hasDM) { eval 'Date_TimeZone();'; if ($@) { die "ERROR: Date::Manip unable to determine TimeZone.\n\nExecute the following command in a shell prompt:\n\tperldoc Date::Manip\nThe section titled TIMEZONES describes valid TimeZones\nand where they can be defined.\n"; } } my $range = lc $ENV{"LOGWATCH_DATE_RANGE"} || "yesterday"; my $period = GetPeriod; $range =~ s/for\s+(?:those|that|this)\s+((year|month|day|hour|minute|second)s?)\s*$//; my ($range1, $range2) = ($range =~ /^between\s+(.*)\s+and\s+(.*)\s*$/); if ($range =~ /^\s*since\s+/) { ($range1) = ($range =~ /\s*since\s+(.*)/); $range2 = "now"; } if ($range1 && $range2 && $hasDM) { # range between two dates specified my $date1 = ParseDate($range1); my $date2 = ParseDate($range2); if ($date1 && $date2) { if (Date_Cmp($date1, $date2) > 0) { # make sure date1 is earlier my $switch_date = $date1; $date1 = $date2; $date2 = $switch_date; } while (Date_Cmp($date1, $date2) < 0) { $time_t[++$#time_t] = UnixDate($date1, "%s"); $date1 = DateCalc($date1, "+1 $period"); } $time_t[++$#time_t] = UnixDate($date2, "%s"); } else { # $date1 or $date2 not valid # set to zero, which indicates it is not parsed $time_t[0] = 0; } } else { # either a single date or we don't have Date::Manip if ($range eq 'yesterday') { $time_t[0] = $time-86400; } elsif ($range eq 'today') { $time_t[0] = $time; } elsif ($range eq 'all') { # set arbitrarily to 1 $time_t[0] = 1; } elsif ($hasDM) { $time_t[0] = UnixDate($range, "%s") || 0; } else { $time_t[0] = 0; } } # this is an optimization when we use Date::Manip, and # the period is either 'month' or 'year'. It is intended # to reduce the number of archived logs searched. # We use the second day of month or year to account for # different timezones. if ($time_t[0] && $hasDM) { my $mod_date = ParseDateString("epoch $time_t[0]"); if ($period =~ /^month|year$/) { # set to beginning of month $mod_date =~ s/\d\d\d\d:\d\d:\d\d$/0200:00:00/; if ($period =~ /^year$/) { # set to beginning of year $mod_date =~ s/\d\d0100:00:00/010200:00:00/; } } $time_t[0] = UnixDate($mod_date, "%s"); } return(@time_t); } =pod =item I This function returns a regexp to filter by date/time =cut sub TimeFilter { my ($format) = $_[0]; my $SearchDate; my $range = lc $ENV{"LOGWATCH_DATE_RANGE"} || "yesterday"; my $debug = $ENV{"LOGWATCH_DEBUG"} || 0; my @time_t = TimeBuild(); # get period my $period = GetPeriod; if ($debug > 5) { print STDERR "\nTimeFilter: Period is $period\n"; } # we need the following bracketed section because of 'last' { if ($period eq 'second') {last;} $format =~ s/%S/../; if ($period eq 'minute') {last;} $format =~ s/%M/../; if ($period eq 'hour') {last;} $format =~ s/%H/../; if ($period eq 'day') {last;} $format =~ s/%a/.../; $format =~ s/%d/../; $format =~ s/%e/../; if ($period eq 'month') {last;} $format =~ s/%b/.../; $format =~ s/%m/../; if ($period eq 'year') {last;} $format =~ s/%y/../; $format =~ s/%Y/..../; } $SearchDate .= "("; for my $time (@time_t) { if ($time) { $SearchDate .= strftime($format, localtime($time)) . "|"; } else { # the following is a string guaranteed to not match $SearchDate .= "Range \"$range\" not understood. "; print STDERR "ERROR: Range \"$range\" not understood\n"; RangeHelpDM; } } # get rid of last character (usually the extra "|") if (length($SearchDate) > 1) { chop($SearchDate); } $SearchDate .= ")"; if ($debug> 5) { # DebugSearchDate sometimes makes it more readable - not used # functionally my $DebugSearchDate = $SearchDate; $DebugSearchDate =~ tr/:/ /; $DebugSearchDate =~ tr/\./ /; $DebugSearchDate =~ tr/ //s; print STDERR "\nTimeFilter: SearchDate is $SearchDate\n"; print STDERR "\nTimeFilter: Debug SearchDate is $DebugSearchDate\n"; } return ($SearchDate); } =back =head1 TAGS In addition to importing each function name explicitly, the following tags can be used. =over 4 =item I<:sort> Imports C, C =item I<:ip> Imports C, C, and C =item I<:dates> Imports C =item I<:all> Imports all importable symbols. =cut 1; # vi: shiftwidth=3 tabstop=3 et logwatch-7.7/override.conf.50000664000211400021140000000003112670102057016214 0ustar logwatchlogwatch.so man5/logwatch.conf.5 logwatch-7.7/HOWTO-Customize-LogWatch0000664000211400021140000005744613771224627017735 0ustar logwatchlogwatchHOWTO-Customize-LogWatch ================================================================================ 1. Table of Contents ==================== 1. Table of Contents 2. Introduction 3. Directory Structure A. Configuration Structure B. Executable Structure 4. Customizing the Configuration 5. Customizing the Scripts 6. Creating New Service Filters A. Logfile Groups B. Service Filter Configuration C. Service Filer Executable D. Shared Script Commands E. Environment Information 7. For More Information This document describes the structure of the Logwatch files in the distribution, how to modify the configuration files for your system, and how to create new service filters. 2. Introduction =============== Logwatch is a system log analyzer and reporter. Usage information about Logwatch can be obtained through the man page: man logwatch The section titled "MORE INFORMATION" in the man page lists additional documentation files available with the distribution. A summary of the command-line switches described in the man page can be obtained with the '--help' option: logwatch --help The rest of this document is intended for those that wish to customize or enhance Logwatch beyond the capabilities provided with the command-line switches. 3. Directory Structure ====================== This section describes the subdirectories and files shipped with the Logwatch distribution, using the names and locations used by default. The directory /usr/share/logwatch contains both the configuration and (perl) executable files. The contents of this directory are the following subdirectories: default.conf: Contains the default configuration files shipped with the Logwatch distribution dist.conf: Contains the configuration files shipped with your specific Operating Systems distribution. lib: Contains perl library files. scripts: Contains the perl executables. The /etc/logwatch directory contains the following subdirectories: conf: Contains the configuration files specific to the system. scripts: Contains the executable scripts specific to the system. A. Configuration Structure -------------------------- The contents of the three directories /usr/share/logwatch/default.conf, /usr/share/logwatch/dist.conf, and /etc/logwatch/conf, all have the same structure: services: This subdirectory contains the configuration files specific to each service. Logwatch determines which services are available by examining the contents of this directory. Each service configuration file is named by its service name with the ".conf" suffix. logfiles: This subdirectory contains the logfile group configuration files. Each logfile group configuration file contains information about one or more log files with the same format. Several services may use the same logfile group configuration file. Each of these configuration files are named by the group name with the ".conf" suffix. Many of the group names are taken from the name of a system log file (such as messages, maillog, secure, etc.), but not always. logwatch.conf: This file contains the defaults for the overall execution of Logwatch, and affect all of its services. Many of its parameters can be overridden by command-line switches when invoking the Logwatch executable, as described in the man page for Logwatch. ignore.conf: This file specifies regular expressions that, when matched by the output of logwatch, will suppress the matching line, regardless of which service is being executed. The /etc/logwatch/conf directory may also contain the file 'override.conf', which is described in section 4, "Customizing the Configuration." B. Executable Structure ----------------------- The contents of the two directories /usr/share/logwatch/scripts and /etc/logwatch/scripts have the same structure: services: This subdirectory contains the executable for each service. Unless otherwise specified in the configuration service file (see above), the executables are written in the perl language. shared: This subdirectory contains executables that may be invoked by more than one configuration service file. logfiles: This subdirectory may contain subdirectories with logfile group names. The executables under each of these subdirectories are automatically invoked when running a service that uses the corresponding logfile group name. 4. Customizing the Configuration ================================ Logwatch can be, and has been, used on many variants of the Linux and UNIX systems. Some distributions that include Logwatch modify the default configuration to comply with the settings of said distributions. Therefore, most people will not need to make any modifications to Logwatch. However, Logwatch, starting with version 7.0, implements a mechanism to allow modifying the local system easier. These modifications may be needed either because the configuration of the service that writes to the system log has been altered from its default, or because the Logwatch user prefers what is reported or how it is reported by Logwatch to be different. You can customize the output of logwatch by modifying variables in the /etc/logwatch/conf directory. Default values are specified in the /usr/share/logwatch/default.conf directory. Your distribution may have set additional defaults in the /usr/share/logwatch/dist.conf directory. All the variables available are declared in the files under these directories. You can change the default values to modify how or what is displayed with logwatch. Two variables are available to all services, and not specified by default. They are the 'Detail' variable and the 'Pre_Ignore' variables. The use of these two variables are described at the end of this section. There are two mechanisms for customizing the variables: 1. The /etc/logwatch/conf directory is first searched for files with the same name and relative location as the /usr/share/logwatch/default.conf directory. Variables declared in these files override the defaults. For example, if file /etc/logwatch/conf/services/sendmail.conf has the single entry: $sendmail_unknownusersthreshold = 5 then the threshold for unknown users is set to five instead of the default of one. All other parameters are not modified. The configuration files have four different types of declarations, determined by the first character in each line: '#': Rest of line is a comment, and is ignored. '$': Rest of first field is a variable '*': Denotes the name of an executable script Other than blank lines, the only other declarations are reserved variable names, such as LogFile, Archive, etc. In general, setting a variable overrides any value previously set. However, the following variables are cumulative: - In logwatch.conf: LogFile, Service - In services/service_name.conf: LogFile - In logfiles/service_name.conf: LogFile, Archive To remove all previous declarations of that variable, set the variable to the empty string. Duplicate values in the cumulative variables are deleted. If an executable script is declared in an /etc/logwatch/conf file, all of the executable script declarations in the corresponding file in /usr/share/logwatch/default.conf or /usr/share/logwatch/dist.conf are ignored. Because of the way variables and executable scripts are declared, the files in /etc/logwatch/conf/ can be created in one of two ways: - you can create a file with only the modified variables (and new executable script declarations, if needed), as described above, or - you can copy an entire configuration file from /usr/share/logwatch/default.conf to its corresponding location in /etc/logwatch/conf, and then modify those lines that require it. Because duplicates are removed from cumulative variables, and new executable script groups override the old ones, the output should be correct. 2. The /etc/logwatch/conf/override.conf file is then searched. The first field in each line may be one of the following: # This character indicates that the rest of the line is a comment, and is ignored. logwatch: This string indicates that the rest of the line is a global configuration option, and uses the same syntax as the /usr/share/logwatch/default.conf/logwatch.conf file. services/service_name: (Where service_name is the name of a service.) This string indicates that the rest of the line is a configuration option for the specified service, and uses the same syntax as the /usr/share/logwatch/default.conf/services files. logfiles/service_name: (Where service_name is the name of a service.) This string indicates that the rest of the line is a configuration option for the specified service, and uses the same syntax as the /usr/share/logwatch/default.conf/logfiles files. For example, if the file /etc/logwatch/conf/override.conf has the single entry: logwatch: Detail = High then the default detail level for all services will be set to High. And, in file override.conf, the following declaration: logfiles/messages: LogFile = syslog will analyze the syslog file (in addition to the default messages file) for certain services. But the following two declarations combined: logfiles/messages: LogFile = logfiles/messages: LogFile = syslog will cause the messages file to be ignored for those same services, and only the syslog file will be used. An earlier reference was made to the two variables available to all services: Detail and Pre_Ignore. Note that neither is preceded by a '$' symbol when used in the configuration file. Specifying a Detail value will override the global Detail level, for that service only. As with the corresponding command option, 'Detail' can be an integer of zero or higher, or the values Low, Medium, or High, which correspond to the integers 0, 5, and 10, respectively. Specifying a Pre_Ignore variable with a regular expression value will use that regular expression as the argument to 'egrep' to filter the log statements. The filter is applied before the service script is run. This is in contrast to the regular expressions in the ignore.conf file (described in Section 3.A above), which filter the output after the service script is run. Also, the declarations in the ignore.conf file are applied to all services. 5. Customizing the Scripts ========================== Similarly to the way you can customize the configuration, as specified in section 4, you can override the default executable scripts. This is accomplished by placing an executable file with the same name and relative path (with respect to /usr/share/logwatch/scripts) under the /etc/logwatch/scripts directory. If such a file is found in the /etc/logwatch/scripts directory, the corresponding file under /usr/share/logwatch/scripts will be ignored. 6. Creating New Service Filters =============================== New services may be created by creating new configuration and executable files, described above, and placing them in the /etc/logwatch directory. This section provides additional details and examples for creating new service filters, but it might be easier to base the new files on the existing configuration and script files under the /usr/share/logwatch directory. A. Logfile Groups ----------------- There is only one required line in the logfile group config file. This statement is called 'LogFile'. # This will be the logfile named 'messages' in the default logfile # directory (probably /var/log). LogFile = messages # You can also give this value with an absolute path. For example: LogFile = /var/log/messages You can have as many LogFile entries as you wish. All the files specified will be merged into one input stream for any filters that use this logfile group. The 'Archive' statement is optional. Specifying it will include the corresponding files in the data stream if the '--archives' option is used. For example: # These 2 'Archive' entries will allow users of most Red Hat Linux # systems to access their archives of the 'messages' logfile: Archive = messages.? # If they configure Compression to be on in /etc/logrotate.conf: Archive = messages.?.gz # It is best just to include both of these so that the logfile group # will work for most systems. When specifying filenames for either the LogFile or Archive statements, you can use standard regexps (for example, *, ?, or [0-9]). In addition, filenames with spaces are possible by enclosing them in single quotes. Similarly, filename case can be preserved by quoting the filename. Single-quoted strings do not expand regexp characters; double-quoted strings do. For either the LogFile or Archive statements, the corresponding files need not exist. In that case, the statement is ignored. Because of this, many Logfile groups have multiple LogFile or Archive statements for many different OS implementations; only those that exist will be used. Now, the general theory is that the LogFile Group should apply the date range requested. If the logfile is in the standard syslog format, you can use the shared script 'ApplyStdDate' to filter out only the appropriate log entries. The way to call shared scripts (located under /usr/share/logwatch/scripts/shared) is: *ApplyStdDate = Anything following the equal sign will be passed to the program as arguments (the equal sign can be eliminated if no arguments are needed). You should look at the current logfile group config files for examples. Finally, if the directory /usr/share/logwatch/scripts/logfiles// exists, any scripts in that directory will be executed. All of these scripts take the contents of all the specified logfiles in through STDIN and output the modified logfile through STDOUT. B. Service Filter Configuration File ------------------------------------ Once you have defined one or more logfile groups (or decided on one or more existing logfile groups), you need to define your service filter. This file needs to be in /etc/logwatch/conf/services/ and it needs to be named service_name.conf, where service_name is the name of the service. You should probably copy an existing config for another service to create a new one. There is only one required line. This is the statement 'LogFile'. The LogFile statement allows you to specify one or more *LogFile Groups* (as described above) that this filter will process. Remember, any filter can process any number of LogFile Groups, and any LogFile Group may contain the data from any number of logfiles (and archives). For a service filter that needs messages from /var/log/messages you would add this line: LogFile = messages NOTE: This is *not* because the name of the logfile is 'messages', but it is because the name of the LogFile Group that has been defined is 'messages'. You can have commands in the form of: *SharedScriptName = Arguments that will execute a script found in the /usr/share/logwatch/scripts/shared/ directory named 'SharedScriptName' with arguments 'Arguments'. This filter will modify the input to the service's filter. You can also have commands in the form: $EnvironmentVariable = Value This command will set the 'EnvironmentVariable' environment variable to the value 'Value'. This environment variable will be accessable by your filter program. You will also usually want to specify a title for your script (new in Logwatch 4.0). If specified, then a start and stop delimiter will be added by Logwatch for your specific service (with your script's output between those delimiters). This will *only* happen if you produce output. If you produce no output, the headers will not be created. Here is how you define your title: Title = "My Service Title" C. Service Filter Executable ---------------------------- Once everything above has been done, you are ready to actually write your filter. This can be done in any language as all it does is: 1) Read logfile entries from STDIN 2) Access some environment variables 3) Generate a report on STDOUT Before you try to write a filter, you should create the filter and make its contents the test script given below. The filter needs to be located in /etc/logwatch/scripts/services/ and named service_name (because you named the config file service_name.conf). ###################### Cut Here ######################### #!/bin/bash # This is as nice script that will show you the lines you will # be processing and reporting on. It will first display the # standard environment variables and then it takes STDIN and # dump it right back out to STDOUT. # These are the standard environment variables. You can define # more in your service config file (see above). echo "Date Range: $LOGWATCH_DATE_RANGE" echo "Detail Level: $LOGWATCH_DETAIL_LEVEL" echo "Temp Dir: $LOGWATCH_TEMP_DIR" echo "Debug Level: $LOGWATCH_DEBUG" # Now take STDIN and dump it to STDOUT cat ###################### Cut Here ######################### If you temporarily replace a script such as 'pam' with the above, you will notice that much has been cut out of /var/log/messages before it gets to this filter. The value of the environment variable LOGWATCH_DETAIL_LEVEL can be any integer. In reality, it is usually 0 (for low), 5 (for medium), and 10 (for high). Your script should only produce output as appropriate. If there are no relevant log entries, no output should be produced. Likewise, if you are reporting two things, such as "Good Logins" and "Bad Logins", you should only produce even the headers when appropriate. For example: Bad Logins: amber (2 time(s)) kirk (3 time(s)) Good Logins: amber (5 time(s)) kirk (10 time(s)) But, if no failed logins occur, you should only output: Good Logins: amber (5 time(s)) kirk (10 time(s)) Note that there is no "Bad Logins:" header as there were no bad logins. You should also use the detail environment variable when deciding what to output. Bad logins might always be displayed, but good logins might only be displayed at higher detail levels. Here is a guide on how you should use the detail setting: 0 (Low): Display only errors and security-related issues 5 (Med): Display anything that a typical administrator would be interested in 10 (High): Display anything that a paranoid administrator would want to see In some cases, you can use a security setting higher than 10. This would be reserved for information so trivial that it would not even interest the US Government. D. Shared Script Commands ------------------------- The way to call commands is: *SharedScriptCommand [= Arguments] Logwatch will search for the command in /usr/share/logwatch/scripts/shared/ and /etc/logwatch/scripts/shared/. The command name is case insensitive and can be used in logfile and service group configuration files. Everything after the equal sign will be passed as arguments to the command. The following shared scripts are shipped with logwatch (they don't accept any arguments unless otherwise mentioned): - ApplyBindDate Filter messages with a time format of '%d-%b-%Y %H:%M:%S' - ApplyEuroDate Filter messages with a time format of '%Y-%m-%d %H:%M:%S' - ApplyHttpDate Filter messages with a time format of '%d/%b/%Y:%H:%M:%S' - ApplyStdDate Without argument filter messages with a time format of '%b %e %H:%M:%S' or '%Y-%m-%dT%H:%M:%S\.[0-9]+[+-][0-9]{2}:[0-9]{2} which is the ISO8601 logformat It accepts one argument which is the filter string, e.g.: *applystddate = "%m-%d-%Y %H:%M:%S" - ApplyTaiDate Filter messages which start with a hex string which represents the seconds since 01.01.1970.' - ApplyUSDate Filter messages with a time format of '%m/%d/%y:%H:%M:%S' - ApplyVsftpdDate Filter messages with a time format of '... %b %e %H:%M:%S 20%y' - EventLogOnlyService Filter messages which match: '... .. ..:..:.. .* MSWinEventLog\t\d+\t$ServiceName\t' It accepts one argument which is the $ServiceName - EventLogRemoveService Will remove the unwanted service from a logfile in a WinEventLog format. Drops messages which match the pattern in EventLogOnlyService. Accepts one argument which is $ServiceName - ExpandRepeats This used to expand "Last message repeated n Times" messages in standard sslog files. But it now ignores these lines, as otherwise the temporary logfiles will be too huge. - HostHash Print all hostnames which occured in a logfile. This matches only at default syslog format: '^... .. ..:..:.. ([\w\-\_]+)' - HostList Write a list of all hostnames which occured in a logfile to $LOGWATCH_TEMP_DIR/hostfile. This matches only at default syslog format: '^... .. ..:..:.. (\S*)' - MultiService This will pick out only the wanted service from a logfile in the standard syslog message format. Case insensitive. Accepts a comma separated list of service names as argument. - OnlyContains Just does a case insensitive egrep. Arguments are passed directly to egrep. - OnlyHost This will pick out only lines from $hostname from a logfile in the standard syslog format. Case insensitive. Set logwatch option LOGWATCH_ONLY_HOSTNAME or pass a comma separated list of hostnames as argument to make this work. - OnlyService This will pick out only the wanted service from a logfile in the standard syslog format. Case insensitive. First argument is the service name. - Remove Just a case insensitive, inverse egrep - RemoveHeaders Remove the beginning of each line of a standard syslog-style, Solaris ID tag style or date-prefix-style logfile. The pattern to remove is configurable and can be passed as the first argument, e.g.: * RemoveHeaders = "\d{4}-\d\d-\d\d \d\d:\d\:\d\d " - RemoveService Remove the unwanted service form a logfile in the standard syslog-style message format. Case insensitive. It accepts one argument which is a comma separated list of service names, e.g.: * RemoveService = "myservice,myotherservice" E. Environment Information -------------------------- The following Informations can be accessed from environment variables inside service scripts, e.g. print "service logfile list: $ENV{'LOGWATCH_LOGFILE_LIST'}" - LOGWATCH_LOGFILE_LIST space separated list of logfiles which are configured for that service. - LOGWATCH_ARCHIVE_LIST space separated list of archive files which are configured for that service. - TODO list other env variables. 7. For More Information ======================= The introduction of this document listed additional sources of information. In addition, the website https://sourceforge.net/projects/logwatch/ contains: - the current (and some archived) distributions of Logwatch - access to a ticket database for bugs, patches, and requests - access to the git repository, for the very latest code. If you do create new services or enhancements that you feel would be useful to other people, please post them under: https://sourceforge.net/p/logwatch/patches/ If you send patches, please make sure that you have the latest version of the file from git, and send the patch file in unified format. Alternatively, create a git merge request. Enhancement suggestions are more likely to be implemented if patch files implementing the change are sent. logwatch-7.7/logwatch.80000664000211400021140000001262714057023200015273 0ustar logwatchlogwatch.\" Process this file with .\" groff -man -Tascii foo.1 .\" .TH LOGWATCH 8 "May 2012" Linux "User Manuals" .SH NAME logwatch \- system log analyzer and reporter .SH SYNOPSIS .B logwatch [--detail .I level .B ] [--logfile .I log-file-group .B ] [--service .I service-name .B ] [--mailto .I address .B ] [--archives] [--range .I range .B ] [--debug .I level .B ] [--filename .I file-name .B ] [--logdir .I directory .B ] [--hostlimit .I hosts .B ] [--hostname .I hostname .B ] [--html_wrap .I number of characters .B ] [--hostformat .I host based options .B ] [--output .I output-type .B ] [--format .I report format .B ] [--subject .I email subject .B ] [--encode .I encoding to use .B ] [--numeric] [--version] [--help|--usage] .SH DESCRIPTION .B Logwatch is a customizable, pluggable log-monitoring system. It will go through your logs for a given period of time and make a report in the areas that you wish with the detail that you wish. Logwatch is being used for Linux and many types of UNIX. .SH OPTIONS .IP "\fB--detail\fR level" This is the detail level of the report. .I level can be a positive integer, or high, med, low, which correspond to the integers 10, 5, and 0, respectively. .IP "\fB--logfile\fR log-file-group" This will force Logwatch to process only the set of logfiles defined by .I log-file-group (i.e. messages, xferlog, ...). Logwatch will therefore process all services that use those logfiles. This option can be specified more than once to specify multiple logfile-groups. .IP "\fB--service\fR service-name" This will force Logwatch to process only the service specified in .I service-name (i.e. login, pam, identd, ...). Logwatch will therefore also process any log-file-groups necessary to process these services. This option can be specified more than once to specify multiple services to process. A useful .I service-name is .I All which will process all services (and logfile-groups) for which you have filters installed. .IP "\fB--mailto\fR address" Mail the results to the email address or user specified in .I address. .IP "\fB--range\fR range" You can specify a date-range to process. Common ranges are .I Yesterday, Today, All, and .I Help. Additional options are listed when invoked with the .I Help parameter. .IP "\fB--archives\fR" Each log-file-group has basic logfiles (i.e. /var/log/messages) as well as archives (i.e. /var/log/messages.? or /var/log/messages.?.gz). When used with "\-\-range all", this option will make Logwatch search through the archives in addition to the regular logfiles. For other values of \-\-range, Logwatch will search the appropriate archived logs. .IP "\fB--debug\fR level" For debugging purposes. .I level can range from 0 to 100. This will .I really clutter up your output. You probably don't want to use this. .IP "\fB--filename\fR file-name" Save the output to .I file-name instead of displaying or mailing it. .IP "\fB--logdir\fR directory" Look in .I directory for log subdirectories or log files first before looking in the default directories. .IP "\fB--hostlimit\fR host1,host2" Limit report to hostname - host1, host2. .IP "\fB--hostname\fR hostname" Use .I hostname for the reports instead of this system's hostname. In addition, if HostLimit is set in the logwatch.conf configuration file (see \fBMORE INFORMATION\fR, below), then only logs from this hostname will be processed (where appropriate). .IP "\fB--html_wrap\fR num-characters" Number of characters that html output should be wrapped to. Default is 80. .IP "\fB--hostformat\fR split" Use .I split approach when formatting report for multiple hosts - none [default], split, splitmail. .IP "\fB--output\fR output-type" Report using .I output-type - stdout [default], mail, file. .IP "\fB--format\fR format" Format report using .I format - text [default], html. .IP "\fB--subject\fR email-subject" Customize the email subject sent by Logwatch. Option \fB--output\fR must be set to mail. .IP "\fB--encode\fR encoding" Encode report using .I encoding - none [default], base64, 7bit, 8bit [same as 'none']. .IP "\fB--numeric\fR" Inhibits additional name lookups, displaying IP addresses numerically. .IP "\fB--usage\fR" Displays usage information .IP "\fB--help\fR" same as \-\-usage. .SH FILES .IP /usr/share/logwatch/ .RS This directory contains all the perl executables and configuration files shipped with the logwatch distribution. .RE .IP /etc/logwatch .RS This directory contains local configuration files that override the default configuration. See \fBMORE INFORMATION\fR below for more information. .RE .SH EXAMPLES .B logwatch --service ftpd-xferlog --range all --detail high --archives .RS This will print out all FTP transfers that are stored in all current and archived xferlogs. .RE .B logwatch --service pam_pwdb --range yesterday --detail high .RS This will print out login information for the previous day... .RE .SH MORE INFORMATION The directory /usr/share/doc/logwatch-* contains several files with additional documentation: .RE .I HOWTO-Customize-LogWatch .RS Documents the directory structure of Logwatch configuration and executable files, and describes how to customize Logwatch by overriding these default files. .RE .I LICENSE .RS Describes the License under which Logwatch is distributed. Additional clauses may be specified in individual files. .RE .I README .RS Describes how to install, where to find it, mailing lists, and other useful information. .SH AUTHOR .RE Kirk Bauer .RE http://sourceforge.net/projects/logwatch logwatch-7.7/logwatch.spec0000644000211400021140000001472114266625341016071 0ustar logwatchlogwatchSummary: Analyzes and Reports on system logs Name: logwatch Version: 7.7 Release: 1 License: MIT Group: Applications/System URL: https://sourceforge.net/projects/logwatch/ BuildArch: noarch Source0: https://sourceforge.net/projects/logwatch/files/%{name}-%{version}/%{name}-%{version}.tar.gz Requires: perl,grep,crontabs BuildRoot: %{_tmppath}/%{name}-%{version}-%{release} %description Logwatch is a customizable, pluggable log-monitoring system. It will go through your logs for a given period of time and make a report in the areas that you wish with the detail that you wish. Easy to use - works right out of the package on many systems. %prep %setup -q %build %install install -m 0755 -d %{buildroot}%{_var}/cache/logwatch install -m 0755 -d %{buildroot}%{_sysconfdir}/logwatch/scripts install -m 0755 -d %{buildroot}%{_sysconfdir}/logwatch/scripts/services install -m 0755 -d %{buildroot}%{_sysconfdir}/logwatch/conf install -m 0755 -d %{buildroot}%{_sysconfdir}/logwatch/conf/logfiles install -m 0755 -d %{buildroot}%{_sysconfdir}/logwatch/conf/services install -m 0755 -d %{buildroot}%{_datadir}/logwatch/default.conf/logfiles install -m 0755 -d %{buildroot}%{_datadir}/logwatch/default.conf/services install -m 0755 -d %{buildroot}%{_datadir}/logwatch/default.conf/html install -m 0755 -d %{buildroot}%{_datadir}/logwatch/dist.conf/logfiles install -m 0755 -d %{buildroot}%{_datadir}/logwatch/dist.conf/services install -m 0755 -d %{buildroot}%{_datadir}/logwatch/scripts/services install -m 0755 -d %{buildroot}%{_datadir}/logwatch/scripts/shared install -m 0755 -d %{buildroot}%{_datadir}/logwatch/lib for i in scripts/logfiles/* ; do if [ $(ls $i | wc -l) -ne 0 ] ; then install -m 0755 -d %{buildroot}%{_datadir}/logwatch/$i install -m 0644 $i/* %{buildroot}%{_datadir}/logwatch/$i fi done install -m 0755 scripts/logwatch.pl %{buildroot}%{_datadir}/logwatch/scripts/logwatch.pl install -m 0644 scripts/services/* %{buildroot}%{_datadir}/logwatch/scripts/services install -m 0644 scripts/shared/* %{buildroot}%{_datadir}/logwatch/scripts/shared install -m 0644 lib/* %{buildroot}%{_datadir}/logwatch/lib install -m 0644 conf/*.conf %{buildroot}%{_datadir}/logwatch/default.conf install -m 0644 conf/logfiles/* %{buildroot}%{_datadir}/logwatch/default.conf/logfiles install -m 0644 conf/services/* %{buildroot}%{_datadir}/logwatch/default.conf/services install -m 0644 conf/html/* %{buildroot}%{_datadir}/logwatch/default.conf/html install -m 0755 -d %{buildroot}%{_mandir}/man1 install -m 0644 amavis-logwatch.1 %{buildroot}%{_mandir}/man1 install -m 0644 postfix-logwatch.1 %{buildroot}%{_mandir}/man1 install -m 0755 -d %{buildroot}%{_mandir}/man5 install -m 0644 logwatch.conf.5 %{buildroot}%{_mandir}/man5 ln -s %{_mandir}/man5/logwatch.conf.5 %{buildroot}%{_mandir}/man5/ignore.conf.5 ln -s %{_mandir}/man5/logwatch.conf.5 %{buildroot}%{_mandir}/man5/override.conf.5 install -m 0755 -d %{buildroot}%{_mandir}/man8 install -m 0644 logwatch.8 %{buildroot}%{_mandir}/man8 rm -f %{buildroot}%{_sysconfdir}/cron.daily/logwatch \ %{buildroot}%{_sbindir}/logwatch install -m 0755 -d %{buildroot}%{_sysconfdir}/cron.daily install -m 0755 scheduler/logwatch.cron %{buildroot}%{_sysconfdir}/cron.daily/0logwatch install -m 0755 -d %{buildroot}%{_sbindir} ln -s %{_datadir}/logwatch/scripts/logwatch.pl %{buildroot}%{_sbindir}/logwatch echo "###### REGULAR EXPRESSIONS IN THIS FILE WILL BE TRIMMED FROM REPORT OUTPUT #####" > %{buildroot}%{_sysconfdir}/logwatch/conf/ignore.conf echo "# Local configuration options go here (defaults are in %{_datadir}/logwatch/default.conf/logwatch.conf)" > %{buildroot}%{_sysconfdir}/logwatch/conf/logwatch.conf echo "# Configuration overrides for specific logfiles/services may be placed here." > %{buildroot}%{_sysconfdir}/logwatch/conf/override.conf %clean rm -rf %{buildroot} %post %pre %preun %postun %files %defattr(-,root,root) %license LICENSE %doc README HOWTO-Customize-LogWatch LICENSE %dir %{_var}/cache/logwatch %dir %{_sysconfdir}/logwatch %dir %{_sysconfdir}/logwatch/* %dir %{_sysconfdir}/logwatch/*/* %{_sbindir}/logwatch %{_datadir}/logwatch %doc %{_mandir}/man*/* %config(noreplace) %{_sysconfdir}/logwatch/conf/*.conf %config(noreplace) %{_sysconfdir}/cron.daily/0logwatch %changelog * Fri Jul 22 2022 Bjorn 7.7 * Sat Jan 22 2022 Jason Pyeron 7.6-1 * Fri Jul 23 2021 Bjorn 7.5.6-1 * Sat Jan 23 2021 Jason Pyeron 7.5.5-1 * Wed Jul 22 2020 Bjorn 7.5.4-1 * Wed Jan 22 2020 Bjorn 7.5.3-1 * Mon Jul 22 2019 Bjorn 7.5.2-1 - Copying LICENSE to doc dir again * Tue Jan 22 2019 Bjorn 7.5.1-1 * Fri Dec 28 2018 Bjorn 7.5.0 - simplified files section - using symbolic links for some man files * Tue Sep 23 2014 Stefan Jakobs 7.4.1-1 - Install other manpages, too * Fri Sep 15 2006 Kirk Bauer 7.3.1-1 - Fixed install script to create empty scripts directory in /etc * Sat Oct 08 2005 Kirk Bauer pre7.0-1 - Numerous changes, most notably a whole new directory structure. * Thu Feb 24 2005 Kirk Bauer 6.0.1-1 - Now includes ignore.conf in the RPM * Mon Nov 03 2003 Kirk Bauer pre5.0-1 - Now can build without change as non-root user * Thu Feb 27 2003 Erik Ogan 4.3.2 - Added libdir & lib/Logwatch.pm * Sun Oct 13 2002 Kirk Bauer pre4.0-14 - Changed the 'logwatch' cron.daily job to '0logwatch' to run before logrotate * Thu Oct 10 2002 Kirk Bauer pre4.0-1 - Cronjob is now just named logwatch and not 00-logwatch * Wed May 01 2002 Kirk Bauer 3.0-6 - up2date packaged... finally! * Wed May 01 2002 Kirk Bauer 3.0-5 - Hopefully now properly included the up2date filter! * Mon Apr 29 2002 Kirk Bauer pre3.0-1 - Now properly includes logfile-specific scripts * Tue Apr 09 2002 Kirk Bauer 2.8-2 - Made man page entry in files list backwards compatible * Thu Mar 28 2002 Kirk Bauer 2.5-2 - Updated new changes from Red Hat's rawhide packaging * Wed Nov 18 1998 Kirk Bauer - Modified to comply with RHCN standards * Mon Feb 23 1998 Kirk Bauer - Minor changes and addition of man-page * Sun Feb 22 1998 Kirk Bauer - initial release logwatch-7.7/postfix-logwatch.10000664000211400021140000010641113076472242016767 0ustar logwatchlogwatch.TH POSTFIX-LOGWATCH 1 .ad .fi .SH NAME postfix-logwatch \- A Postfix log parser and analysis utility .SH "SYNOPSIS" .na .nf .fi \fBpostfix-logwatch\fR [\fIoptions\fR] [\fIlogfile ...\fR] .SH DESCRIPTION .ad .fi The \fBpostfix-logwatch\fR(1) utility is a Postfix MTA log parser that produces summaries, details, and statistics regarding the operation of Postfix. .PP This utility can be used as a standalone program, or as a Logwatch filter module to produce Postfix summary and detailed reports from within Logwatch. .PP \fBPostfix-logwatch\fR is able to produce a wide range of reports with data grouped and sorted as much as possible to reduce noise and highlight patterns. Brief summary reports provide a quick overview of general Postfix operations and message delivery, calling out warnings that may require attention. Detailed reports provide easy to scan, hierarchically-arranged and organized information, with as much or little detail as desired. .PP \fBPostfix-logwatch\fR outputs two principal sections: a \fBSummary\fR section and a \fBDetailed\fR section. For readability and quick scanning, all event or hit counts appear in the left column, followed by brief description of the event type, and finally additional statistics or count representations may appear in the rightmost column. The following segment from a sample Summary report illustrates: .RS 4 .nf ****** Summary ******************************************** 81 *Warning: Connection rate limit reached (anvil) 146 Warned 68.310M Bytes accepted 71,628,177 97.645M Bytes delivered 102,388,245 ======== ================================================ 3464 Accepted 41.44% 4895 Rejected 58.56% -------- ------------------------------------------------ 8359 Total 100.00% ======== ================================================ .fi .RE 0 The report warns that anvil's connection rate was hit 81 times, a Postfix access check WARN action was logged 146 times, and a total of 68.310 megabytes (71,628,177 bytes) were accepted into the Postfix system, delivering 97.645 megabytes of data (due to multiple recipients). The Accepted and Rejected lines show that Postfix accepted 3464 (41.44% of the total messages) and rejected 4895 (the remaining 58.56%) of the 8359 total messages (temporary rejects show up elsewhere). .PP There are dozens of sub-sections available in the \fBDetailed\fR report, each of whose output can be controlled in various ways. Each sub-section attempts to group and present the most meaningful data at superior levels, while pushing less useful or \fInoisy\fR data towards inferior levels. The goal is to provide as much benefit as possible from smart grouping of data, to allow faster report scanning, pattern identification, and problem solving. Data is always sorted in descending order by count, and then numerically by IP address or alphabetically as appropriate. .PP The following MX errors segment from a sample \fBDetailed\fR report illustrates the basic hierarchical level structure of \fBpostfix-logwatch\fR: .RS 4 .nf ****** Detailed ******************************************* 261 MX errors -------------------------------------- 261 Unable to look up MX host 222 Host not found 73 foolishspammer.local 60 completely.bogus.domain.example 11 friend.example.com 39 No address associated with hostname 23 dummymx.sample.net 16 pushn.spam.sample.com .fi .RE 0 .PP The \fBpostfix-logwatch\fR utility reads from STDIN or from the named Postfix \fIlogfile\fR. Multiple \fIlogfile\fR arguments may be specified, each processed in order. The user running \fBpostfix-logwatch\fR must have read permission on each named log file. .PP .SS Options The options listed below affect the operation of \fBpostfix-logwatch\fR. Options specified later on the command line override earlier ones. Any option may be abbreviated to an unambiguous length. .IP "\fB-f \fIconfig_file\fR" .PD 0 .IP "\fB--config_file \fIconfig_file\fR" .PD Use an alternate configuration file \fIconfig_file\fR instead of the default. This option may be used more than once. Multiple configuration files will be processed in the order presented on the command line. See \fBCONFIGURATION FILE\fR below. .IP "\fB--debug \fIkeywords\fR" Output debug information during the operation of \fBpostfix-logwatch\fR. The parameter \fIkeywords\fR is one or more comma or space separated keywords. To obtain the list of valid keywords, use --debug xxx where xxx is any invalid keyword. .IP "\fB--[no]delays\fR" Enables (disables) output of the message delays percentiles report. The delays percentiles report shows percentiles for each of the 4 delivery latency times reported by Postfix (available in version 2.3 and later) in the form \fBdelays=\fIa\fR/\fIb\fR/\fIc\fR/\fId\fR, where \fIa\fR is the amount of time before the active queue (includes time for previous delivery attempts and time in the deferred queue), \fIb\fR is the amount of time in the active queue up to delivery agent handoff, \fIc\fR is the amount of time spent making connections (including DNS, HELO and TLS) and \fId\fR is the amount of time spent delivering the message. The total delay shown comes from the \fBdelay=\fR field in a message delivery log line. \fBNote:\fR This report may consume a large amount of memory; if you have no use for it, disable the delays report. .IP "\fB--delays_percentiles \fIp1 [p2 ...]\fR" Specifies the percentiles to be used in the message delays percentiles report. The percentiles \fIp1\fR, \fIp2\fR, \fI...\fR range from 0 to 100, inclusively. The order of the list is not sorted - the report will output the percentiles columns in the order you specify. .IP "\fB--detail \fIlevel\fR" Sets the maximum detail level for \fBpostfix-logwatch\fR to \fIlevel\fR. This option is global, overriding any other output limiters described below. The \fBpostfix-logwatch\fR utility produces a \fBSummary\fR section, a \fBDetailed\fR section, and additional report sections. With \fIlevel\fR less than 5, \fBpostfix-logwatch\fR will produce only the \fBSummary\fR section. At \fIlevel\fR 5 and above, the \fBDetailed\fR section, and any additional report sections are candidates for output. Each incremental increase in \fIlevel\fR generates one additional hierarchical sub-level of output in the \fBDetailed\fR section of the report. At \fIlevel\fR 10, all levels are output. Lines that exceed the maximum report width (specified with \fBmax_report_width\fR) will be cut. Setting \fIlevel\fR to 11 will prevent lines in the report from being cut (see also \fB--line_style\fR). .IP "\fB--help\fR" Print usage information and a brief description about command line options. .IP "\fB--ignore_service \fIpattern\fR" Ignore log lines that contain the postfix service name \fBpostfix/\fIservice\fR. The parameter \fIservice\fR is a regular expression. \fBNote:\fR if you use parenthesis in your regular expression, be sure they are cloistering and not capturing: use \fB(?:\fIpattern\fB)\fR instead of \fB(\fIpattern\fB)\fR. .IP "\fB--ipaddr_width \fIwidth\fR" Specifies that IP addresses in address/hostname pairs should be printed with a field width of \fIwidth\fR characters. Increasing the default may be useful for systems using long IPv6 addresses. .IP "\fB-l limiter=levelspec\fR" .PD 0 .IP "\fB--limit limiter=levelspec\fR" .PD Sets the level limiter \fIlimiter\fR with the specification \fIlevelspec\fR. .IP "\fB--line_style \fIstyle\fR" Specifies how to handle long report lines. Three styles are available: \fBfull\fR, \fBtruncate\fR, and \fBwrap\fR. Setting \fIstyle\fR to \fBfull\fR will prevent cutting lines to \fBmax_report_width\fR; this is what occurs when \fBdetail\fR is 11 or higher. When \fIstyle\fR is \fBtruncate\fR (the default), long lines will be truncated according to \fBmax_report_width\fR. Setting \fIstyle\fR to \fBwrap\fR will wrap lines longer than \fBmax_report_width\fR such that left column hit counts are not obscured. This option takes precedence over the line style implied by the \fBdetail\fR level. The options \fB--full\fR, \fB--truncate\fR, and \fB--wrap\fR are synonyms. .IP "\fB--[no]long_queue_ids\fR" Enables (disables) interpretation of long queue IDs in Postfix (>= 2.9) logs. .IP "\fB--nodetail\fR" Disables the \fBDetailed\fR section of the report, and all supplemental reports. This option provides a convenient mechanism to quickly disable all sections under the \fBDetailed\fR report, where subsequent command line options may re-enable one or more sections to create specific reports. .IP "\fB--[no]summary\fR" .IP "\fB--show_summary\fR" Enables (disables) displaying of the the \fBSummary\fR section of the report. The variable postfix_Show_Summary in used in a configuration file. .IP "\fB--recipient_delimiter \fIdelimiter\fR" Split email delivery addresses using the recipient delimiter character \fIdelimiter\fR. This should generally match the \fBrecipient_delimiter\fR specified in the Postfix parameter file \fBmain.cf\fR, or the default value indicated in \fBpostconf -d recipient_delimiter\fR. This is very useful for obtaining per-alias statistics when a recipient delimiter is used for mail delivery. .IP "\fB--reject_reply_patterns \fIr1 [r2 ...]\fR" Specifies the list of reject reply patterns used to create reject groups. Each entry in the list \fIr1 [r2 ...]\fR must be either a three character regular expression reply code of the form [45][0-9.][0-9.], or the word "Warn". The "." in the regular expression is a literal dot which matches any reject reply subcode; this wildcarding allows creation of broad rejects groups. List order is preserved, in that reject reports will be output in the same order as the entries in the list. Specific reject reply codes will take priority over wildcard patterns, regardless of the list order. The default list is "5.. 4.. Warn", which creates three groups of rejects: permanent rejects, temporary reject failures, and reject warnings (as in warn_if_reject). This feature allows, for example, distinguishing 421 transmission channel closures from 45x errors (eg. 450 mailbox unavailable, 451 local processing errors, 452 insufficient storage). Such a grouping would be configured with the list: "421 4.. 5.. Warn". See RFC 2821 for more information about reply codes. See also \fBCONFIGURATION FILE\fR regarding using \fBreject_reply_patterns\fR within a configuration file. .IP "\fB--[no]sect_vars\fR" .PD 0 .IP "\fB--show_sect_vars \fIboolean\fR" .PD Enables (disables) supplementing each \fBDetailed\fR section title with the name of that section's level limiter. The name displayed is the command line option (or configuration file variable) used to limit that section's output. . With the large number of level limiters available in \fBpostfix-logwatch\fR, this a convenient mechanism for determining exactly which level limiter affects a section. .IP "\fB--syslog_name \fInamepat\fR" Specifies the syslog service name that \fBpostfix-logwatch\fR uses to match syslog lines. Only log lines whose service name matches the perl regular expression \fInamepat\fR will be used by \fBpostfix-logwatch\fR; all non-matching lines are silently ignored. This is useful when a pre-installed Postfix package uses a name other than the default (\fBpostfix\fR), or when multiple Postfix instances are in use and per-instance reporting is desired. The pattern \fInamepat\fR should match the \fBsyslog_name\fR configuration parameter specified in the Postfix parameter file \fBmain.cf\fR, the master control file \fBmaster.cf\fR, or the default value as indicated by the output of \fBpostconf -d syslog_name\fR. \fBNote:\fR if you use parenthesis in your regular expression, be sure they are cloistering and not capturing: use \fB(?:\fIpattern\fB)\fR instead of \fB(\fIpattern\fB)\fR. .IP "\fB--[no]unknown\fR" .PD 0 .IP "\fB--show_unknown \fIboolean\fR" .PD Enables (disables) display of the postfix-generated name of 'unknown' in formated IP/hostname pairs in \fBDetailed\fR reports. Default: enabled. .IP "\fB--version\fR" Print \fBpostfix-logwatch\fR version information. .SS Level Limiters .PP The output of every section in the \fBDetailed\fR report is controlled by a level limiter. The name of the level limiter variable will be output when the \fBsect_vars\fR option is set. Level limiters are set either via command line in standalone mode with \fB--limit \fIlimiter\fB=\fIlevelspec\fR option, or via configuration file variable \fB$postfix_\fIlimiter\fB=\fIlevelspec\fR. Each limiter requires a \fIlevelspec\fR argument, which is described below in \fBLEVEL CONTROL\fR. The list of level limiters is shown below. There are several level limiters that control reject sub-sections (eg. \fBrejectbody\fR, \fBrejectsender\fR, etc.). Because the list of reject variants is not known until runtime after \fBreject_reply_patterns\fR is seen, these reject limiters are shown below generically, with the prefix \fB###\fR. To use one of these reject limiters, substitute \fB###\fR with one of the reject reply codes in effect, replacing each dot with an \fBx\fR character. For example, using the default \fBreject_reply_patterns\fR list of "5.. 4.. Warn", three \fBrejectbody\fR variants are valid: \fB--limit 5xxrejectbody\fR, \fB--limit 4xxrejectbody\fR and \fB--limit warnrejectbody\fR. As a convenience, you may entirely eliminate the \fB###\fR prefix, and instead use the bare \fBreject\fIXXX\fR option, and all reject level limiter variations will be auto-generated based on the \fBreject_reply_patterns\fR list. For example, the command line segment: .nf ... --reject_reply_patterns "421 5.." \\ --limit rejectrbl="1:10:" .fi would automatically become: .nf ... --reject_reply_patterns "421 5.." \\ --limit 421rejectrbl="1:10:" --limit 5xxrejectrbl="1:10:" .fi See \fBreject_reply_patterns\fR above, and comments in the configuration file \fBpostfix-logwatch.conf\fR. .de TQ . br . ns . TP \\$1 .. [ THIS SECTION IS NOT YET COMPLETE ] .PD 0 .IP "\fBAttrError" Errors obtaining attribute data from service. .IP "\fBBCCed" Messages that triggered access, header_checks or body_checks BCC action. (postfix 2.6 experimental branch) .IP "\fBBounceLocal" .IP "\fBBounceRemote" Local and remote bounces. A bounce is considered a local bounce if the relay was one of none, local, virtual, avcheck, maildrop or 127.0.0.1. .IP "\fBByIpRejects" Regrouping by client host IP address of all 5xx (permanent) reject variants. .IP "\fBCommunicationError" Postfix errors talking to one of its services. .IP "\fBAnvil" Anvil rate or concurrency limits. .IP "\fBConnectionInbound" Connections made to the \fBsmtpd\fR server. .IP "\fBConnectionLostInbound" Connections lost to the \fBsmtpd\fR server. .IP "\fBConnectionLostOutbound" Connections lost during \fBsmtp\fR communications with remote MTA. .IP "\fBConnectToFailure" Failures reported by \fBsmtp\fR when connecting to remote MTA. .IP "\fBDatabaseGeneration" Warnings noted when binary database map file requires \fBpostmap\fR update from newer source file. .IP "\fBDeferrals" .IP "\fBDeferred" Message delivery deferrals. A single \fBdeferred\fR message will have one or more \fBdeferrals\fR many times. .IP "\fBDeliverable" Address verification indicates recipient address is deliverable. .IP "\fBDelivered" Number of messages handed-off to a delivery agent such as local or virtual. .IP "\fBDiscarded" Messages that triggered access, header_checks or body_checks DISCARD action. .IP "\fBDNSError" Any one of several errors encountered during DNS lookups. .IP "\fBEnvelopeSenderDomains" List of sending domains. (2 levels: envelope sender domain, localpart) .IP "\fBEnvelopeSenders" List of envelope senders. (1 level: envelope sender) .IP "\fBError" Postfix general \fBerror\fR messages. .IP "\fBFatalConfigError" Fatal main.cf or master.cf configuration errors. .IP "\fBFatalError" Postfix general \fBfatal\fR messages. .IP "\fBFiltered" Messages that triggered access, header_checks or body_checks FILTER action. .IP "\fBForwarded" Messages forwarded by MDA for one address class to another (eg. local -> virtual). .IP "\fBHeloError" XXXXXXXXXXX .IP "\fBHold" Messages that were placed on hold by postsuper, or triggered by access, header_checks or body_checks HOLD action. .IP "\fBHostnameValidationError" Invalid hostname detected. .IP "\fBHostnameVerification" Lookup of hostname does not map back to the IP of the peer (ie. the remote system connecting to \fBsmtpd\fR). Also known as forward-confirmed reverse DNS (FCRDNS). When the reverse name has no DNS entry, the message "host not found, try again" is included; otherwise, it is not (e.g. when the reverse has some IP address, but not the one Postfix expects). .IP "\fBIllegalAddrSyntax" Illegal syntax in an email address provided during the MAIL FROM or RCPT TO dialog. .IP "\fBLdapError" Any LDAP errors during LDAP lookup. .IP "\fBMailerLoop" An MX lookup for the best mailer to use to deliver mail would result in a sending to ourselves. .IP "\fBMapProblem" Problem with an access table map that needs correcting. .IP "\fBMessageWriteError" Postfix encountered an error when trying to create a message file somewhere in the spool directory. .IP "\fBNumericHostname" A hostname was found that was numeric, instead of alphabetic. .IP "\fBPanicError" Postfix general \fBpanic\fR messages. .IP "\fBPixWorkaround" Workarounds were enabled to avoid remote Cisco PIX SMTP "fixups". .IP "\fBPolicydWeight" Summarization of policyweight/policydweight results. .IP "\fBPolicySpf" Summarization of PolicySPF results. .IP "\fBPostgrey" Summarization of Postgrey results. .IP "\fBPostscreen" Summarization of 2.7's postscreen and verify services. .IP "\fBDNSBLog" Summarization of 2.7's dnsblog service. .IP "\fBPrepended" Messages that triggered header_checks or body_checks PREPEND action. .IP "\fBProcessExit" Postfix services that exited unexpectedly. .IP "\fBProcessLimit" A Postfix service has reached or exceeded the maximum number of processes allowed. .IP "\fBQueueWriteError" Problems writing a Postfix queue file. .IP "\fBRblError" Lookup errors for RBLs. .IP "\fBRedirected" Messages that triggered access, header_checks or body_checks REDIRECT action. .IP "\fB###RejectBody" Messages that triggered body_checks REJECT action. .IP "\fB###RejectClient" Messages rejected by client access controls (smtpd_client_restrictions). .IP "\fB###RejectConfigError" Message rejected due to server configuration errors. .IP "\fB###RejectContent" Messages rejected by message_reject_characters. .IP "\fB###RejectData" Messages rejected at DATA stage in SMTP conversation (smtpd_data_restrictions). .IP "\fB###RejectEtrn" Messages rejected at ETRN stage in SMTP conversation (smtpd_etrn_restrictions). .IP "\fB###RejectHeader" Messages that triggered header_checks REJECT action. .IP "\fB###RejectHelo" Messages rejected at HELO/EHLO stage in SMTP conversation (smtpd_helo_restrictions). .IP "\fB###RejectInsufficientSpace" Messages rejected due to insufficient storage space. .IP "\fB###RejectLookupFailure" Messages rejected due to temporary DNS lookup failures. .IP "\fB###RejectMilter" Milter rejects. No reject reply code is available for these rejects, but an extended 5.7.1 DSN is provided. These rejects are forced into the generic 5xx rejects group. If you redefine \fBreject_reply_patterns\fR such that it does not contain the pattern \fB5..\fR, milter rejects will not be output. .IP "\fB###RejectRbl" Messages rejected by an RBL hit. .IP "\fB###RejectRecip" Messages rejected by recipient access controls (smtpd_recipient_restrictions). .IP "\fB###RejectRelay" Messages rejected by relay access controls. .IP "\fB###RejectSender" Messages rejected by sender access controls (smtpd_sender_restrictions). .IP "\fB###RejectSize" Messages rejected due to excessive message size. .IP "\fB###RejectUnknownClient" Messages rejected by unknown client access controls. .IP "\fB###RejectUnknownReverseClient" Messages rejected by unknown reverse client access controls. .IP "\fB###RejectUnknownUser" Messages rejected by unknown user access controls. .IP "\fB###RejectUnverifiedClient" Messages rejected by unverified client access controls. .IP "\fB###RejectVerify" Messages rejected dueo to address verification failures. .IP "\fBReplaced" Messages that triggered header_checks or body_checks REPLACE action. .IP "\fBReturnedToSender" Messages returned to sender due to exceeding queue lifetime (maximal_queue_lifetime). .IP "\fBSaslAuth" SASL authentication successes, includes SASL method, username, and sender when present. .IP "\fBSaslAuthFail" SASL authentication failures. .IP "\fBSent" Messages sent via the SMTP delivery agent. .IP "\fBSentLmtp" Messages sent via the LMTP delivery agent. .IP "\fBSmtpConversationError" Errors during the SMTP/ESMTP dialog. .IP "\fBSmtpProtocolViolation" Protocol violation during the SMTP/ESMTP dialog. .IP "\fBStartupError" Errors during Postfix server startup. .IP "\fBTimeoutInbound" Connections to \fBsmtpd\fR that timed out. .IP "\fBTlsClientConnect" TLS client connections. .IP "\fBTlsOffered" TLS communication offered. .IP "\fBTlsServerConnect" TLS server connections. .IP "\fBTlsUnverified" Unverified TLS connections. .IP "\fBUndeliverable" Address verification indicates recipient address is undeliverable. .IP "\fBWarn" Messages that triggered access, header_checks or body_checks WARN action. .IP "\fBWarnConfigError" Warnings regarding Postfix configuration errors. .IP "\fBWarningsOther" Postfix general \fBwarning\fR messages. .PD .SH LEVEL CONTROL .ad .fi The \fBDetailed\fR section of the report consists of a number of sub-sections, each of which is controlled both globally and independently. Two settings influence the output provided in the \fBDetailed\fR report: a global detail level (specified with \fB--detail\fR) which has final (big hammer) output-limiting control over the \fBDetailed\fR section, and sub-section specific detail settings (small hammer), which allow further limiting of the output for a sub-section. Each sub-section may be limited to a specific depth level, and each sub-level may be limited with top N or threshold limits. The \fIlevelspec\fR argument to each of the level limiters listed above is used to accomplish this. It is probably best to continue explanation of sub-level limiting with the following well-known outline-style hierarchy, and some basic examples: .nf level 0 level 1 level 2 level 3 level 4 level 4 level 2 level 3 level 4 level 4 level 4 level 3 level 4 level 3 level 1 level 2 level 3 level 4 .fi .PP The simplest form of output limiting suppresses all output below a specified level. For example, a \fIlevelspec\fR set to "2" shows only data in levels 0 through 2. Think of this as collapsing each sub-level 2 item, thus hiding all inferior levels (3, 4, ...), to yield: .nf level 0 level 1 level 2 level 2 level 1 level 2 .fi .PP Sometimes the volume of output in a section is too great, and it is useful to suppress any data that does not exceed a certain threshold value. Consider a dictionary spam attack, which produces very lengthy lists of hit-once recipient email or IP addresses. Each sub-level in the hierarchy can be threshold-limited by setting the \fIlevelspec\fR appropriately. Setting \fIlevelspec\fR to the value "2::5" will suppress any data at level 2 that does not exceed a hit count of 5. .PP Perhaps producing a top N list, such as top 10 senders, is desired. A \fIlevelspec\fR of "3:10:" limits level 3 data to only the top 10 hits. .PP With those simple examples out of the way, a \fIlevelspec\fR is defined as a whitespace- or comma-separated list of one or more of the following: .IP "\fIl\fR" Specifies the maximum level to be output for this sub-section, with a range from 0 to 10. if \fIl\fR is 0, no levels will be output, effectively disabling the sub-section (level 0 data is already provided in the Summary report, so level 1 is considered the first useful level in the \fBDetailed\fR report). Higher values will produce output up to and including the specified level. .IP "\fIl\fB.\fIn\fR" Same as above, with the addition that \fIn\fR limits this section's level 1 output to the top \fIn\fR items. The value for \fIn\fR can be any integer greater than 1. (This form of limiting has less utility than the syntax shown below. It is provided for backwards compatibility; users are encouraged to use the syntax below). .IP "\fIl\fB:\fIn\fB:\fIt\fR" This triplet specifies level \fIl\fR, top \fIn\fR, and minimum threshold \fIt\fR. Each of the values are integers, with \fIl\fR being the level limiter as described above, \fIn\fR being a top \fIn\fR limiter for the level \fIl\fR, and \fIt\fR being the threshold limiter for level \fIl\fR. When both \fIn\fR and \fIt\fR are specified, \fIn\fR has priority, allowing top \fIn\fR lists (regardless of threshold value). If the value of \fIl\fR is omitted, the specified values for \fIn\fR and/or \fIt\fR are used for all levels available in the sub-section. This permits a simple form of wildcarding (eg. place minimum threshold limits on all levels). However, specific limiters always override wildcard limiters. The first form of level limiter may be included in \fIlevelspec\fR to restrict output, regardless of how many triplets are present. .PP All three forms of limiters are effective only when \fBpostfix-logwatch\fR's detail level is 5 or greater (the \fBDetailed\fR section is not activated until detail is at least 5). .PP See the \fBEXAMPLES\fR section for usage scenarios. .SH CONFIGURATION FILE .ad \fBPostfix-logwatch\fR can read configuration settings from a configuration file. Essentially, any command line option can be placed into a configuration file, and these settings are read upon startup. Because \fBpostfix-logwatch\fR can run either standalone or within Logwatch, to minimize confusion, \fBpostfix-logwatch\fR inherits Logwatch's configuration file syntax requirements and conventions. These are: .IP \(bu 4'. White space lines are ignored. .IP \(bu 4'. Lines beginning with \fB#\fR are ignored .IP \(bu 4'. Settings are of the form: .nf \fIoption\fB = \fIvalue\fR .fi .IP \(bu 4'. Spaces or tabs on either side of the \fB=\fR character are ignored. .IP \(bu 4'. Any \fIvalue\fR protected in double quotes will be case-preserved. .IP \(bu 4'. All other content is reduced to lowercase (non-preserving, case insensitive). .IP \(bu 4'. All \fBpostfix-logwatch\fR configuration settings must be prefixed with "\fB$postfix_\fR" or \fBpostfix-logwatch\fR will ignore them. .IP \(bu 4'. When running under Logwatch, any values not prefixed with "\fB$postfix_\fR" are consumed by Logwatch; it only passes to \fBpostfix-logwatch\fR (via environment variable) settings it considers valid. .IP \(bu 4'. The values \fBTrue\fR and \fBYes\fR are converted to 1, and \fBFalse\fR and \fBNo\fR are converted to 0. .IP \(bu 4'. Order of settings is not preserved within a configuration file (since settings are passed by Logwatch via environment variables, which have no defined order). .PP To include a command line option in a configuration file, prefix the command line option name with the word "\fB$postfix_\fR". The following configuration file setting and command line option are equivalent: .nf \fB$postfix_Line_Style = Truncate\fR \fB--line_style Truncate\fR .fi Level limiters are also prefixed with \fB$postfix_\fR, but on the command line are specified with the \fB--limit\fR option: .nf \fB$postfix_Sent = 2\fR \fB--limit Sent=2\fR .fi The order of command line options and configuration file processing occurs as follows: 1) The default configuration file is read if it exists and no \fB--config_file\fR was specified on a command line. 2) Configuration files are read and processed in the order found on the command line. 3) Command line options override any options already set either via command line or from any configuration file. Command line options are interpreted when they are seen on the command line, and later options will override previously set options. The notable exception is with limiter variables, which are interpreted in the order found, but only after all other options have been processed. This allows \fB--reject_reply_patterns\fR to determine the dynamic list of the various reject limiters. See also \fB--reject_reply_patterns\fR. .SH "EXIT STATUS" .na .nf .ad .fi The \fBpostfix-logwatch\fR utility exits with a status code of 0, unless an error occurred, in which case a non-zero exit status is returned. .SH "EXAMPLES" .na .nf .ad .fi .SS Running Standalone \fBNote:\fR \fBpostfix-logwatch\fR reads its log data from one or more named Postfix log files, or from STDIN. For brevity, where required, the examples below use the word \fIfile\fR as the command line argument meaning \fI/path/to/postfix.log\fR. Obviously you will need to substitute \fIfile\fR with the appropriate path. .nf .PP To run \fBpostfix-logwatch\fR in standalone mode, simply run: .nf .RS 4 .PP \fBpostfix-logwatch \fIfile\fR .RE 0 .nf .PP A complete list of options and basic usage is available via: .nf .RS 4 .PP \fBpostfix-logwatch --help\fR .RE 0 .nf .PP To print a summary only report of Postfix log data: .nf .RS 4 .PP \fBpostfix-logwatch --detail 1 \fIfile\fR .RE 0 .fi .PP To produce a summary report and a one-level detail report for May 25th: .nf .RS 4 .PP \fBgrep 'May 25' \fIfile\fB | postfix-logwatch --detail 5\fR .RE 0 .fi .PP To produce only a top 10 list of Sent email domains, the summary report and detailed reports are first disabled. Since commands line options are read and enabled left-to-right, the Sent section is re-enabled to level 1 with a level 1 top 10 limiter: .nf .RS 4 .PP \fBpostfix-logwatch --nosummary --nodetail --limit sent='1 1:10:' \fIfile\fR .RE 0 .fi .PP The following command and its sample output shows a more complex level limiter example. The command gives the top 3 Sent email addresses from the top 5 domains, in addition, all level 3 items with a hit count of 2 or less are suppressed (in the Sent sub-section, this happens to be email's Original To address). Ellipses indicate top N or threshold-limited data: .nf .RS 4 .PP \fBpostfix-logwatch --nosummary --nodetail \\ --limit sent '1:5: 2:3: 3::2' \fIfile\fR .nf 1762 Sent via SMTP ----------------------------------- 352 example.com 310 joe 255 joe.bob@virtdomain.example.com 7 info@virtdomain.example.com 21 pooryoda3 11 hot93uh ... 244 sample.net 97 buzz 26 leroyjones 14 sally ... 152 example.net 40 jim_jameson 23 sam_sampson 19 paul_paulson ... 83 sample.us 44 root 39 jenny1 69 dom3.example.us 10 kay 7 ron 6 mrsmith ... ... .fi .RE 0 .fi .PP The next command uses both \fBreject_reply_patterns\fR and level limiters to see 421 RBL rejects, threshold-limiting level 2 output to hits greater than 5 (level 2 in the Reject RBL sub-section is the client's IP address / hostname pair). This makes for a very nice RBL offenders list, shown in the sample output (note the use of the unambiguous, abbreviated command line option reject_reply_pat): .nf .RS 4 .PP \fBpostfix-logwatch --reject_reply_pat '421 4.. 5.. Warn' \\ --nosummary --nodetail --limit 421rejectrbl='2 2::5' \fIfile\fR .nf 300 421 Reject RBL --------------------------------------- 243 zen.spamhaus.org=127.0.0.2 106 10.0.0.129 129.0.0.example.com 41 192.168.10.70 hostx10.sample.net 40 192.168.42.39 hostz42.sample.net 15 10.1.1.152 dsl-10-1-1-152.example.us 14 10.10.10.122 mail122.sample.com 7 192.168.3.44 smalltime-spammer.example.com ... 48 zen.spamhaus.org=127.0.0.4 17 10.29.124.92 10-29-124-92.adsl-static.sample.us ... 8 zen.spamhaus.org=127.0.0.11 ... 1 zen.spamhaus.org=127.0.0.10 ... .fi .RE 4 .SS Running within Logwatch \fBNote:\fR Logwatch versions prior to 7.3.6, unless configured otherwise, required the \fB--print\fR option to print to STDOUT instead of sending reports via email. Since version 7.3.6, STDOUT is the default output destination, and the \fB--print\fR option has been replaced by \fB--output stdout\fR. Check your configuration to determine where report output will be directed, and add the appropriate option to the commands below. .PP To print a summary report for today's Postfix log data: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 1\fR .RE 0 .nf .PP To print a report for today's Postfix log data, with one level of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 5\fR .RE 0 .fi .PP To print a report for yesterday, with two levels of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service postfix --range yesterday --detail 6\fR .RE 0 .fi .PP To print a report from Dec 12th through Dec 14th, with four levels of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service postfix --range \\ 'between 12/12 and 12/14' --detail 8\fR .RE 0 .PP To print a report for today, with all levels of detail: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 10\fR .RE 0 .PP Same as above, but leaves long lines uncut: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 11\fR .RE 0 .SH "ENVIRONMENT" .na .nf .ad .fi The \fBpostfix-logwatch\fR program uses the following (automatically set) environment variables when running under Logwatch: .IP \fBLOGWATCH_DETAIL_LEVEL\fR This is the detail level specified with the Logwatch command line argument \fB--detail\fR or the \fBDetail\fR setting in the ...conf/services/postfix.conf configuration file. .IP \fBLOGWATCH_DEBUG\fR This is the debug level specified with the Logwatch command line argument \fB--debug\fR. .IP \fBpostfix_\fIxxx\fR The Logwatch program passes all settings \fBpostfix_\fIxxx\fR in the configuration file ...conf/services/postfix.conf to the \fBpostfix\fR filter (which is actually named .../scripts/services/postfix) via environment variable. .SH "FILES" .na .nf .SS Standalone mode .IP "/usr/local/bin/postfix-logwatch" The \fBpostfix-logwatch\fR program .IP "/usr/local/etc/postfix-logwatch.conf" The \fBpostfix-logwatch\fR configuration file in standalone mode .SS Logwatch mode .IP "/etc/logwatch/scripts/services/postfix" The Logwatch \fBpostfix\fR filter .IP "/etc/logwatch/conf/services/postfix.conf" The Logwatch \fBpostfix\fR filter configuration file .SH "SEE ALSO" .na .nf logwatch(8), system log analyzer and reporter .SH "README FILES" .na .ad .nf README, an overview of \fBpostfix-logwatch\fR Changes, the version change list history Bugs, a list of the current bugs or other inadequacies Makefile, the rudimentary installer LICENSE, the usage and redistribution licensing terms .SH "LICENSE" .na .nf .ad Covered under the included MIT/X-Consortium License: http://www.opensource.org/licenses/mit-license.php .SH "AUTHOR(S)" .na .nf Mike Cappella .fi The original \fBpostfix\fR Logwatch filter was written by Kenneth Porter, and has had many contributors over the years. They are entirely not responsible for any errors, problems or failures since the current author's hands have touched the source code. logwatch-7.7/logwatch.conf.50000664000211400021140000000175213411252162016215 0ustar logwatchlogwatch.\" Written by Ivana Varekova . .TH LOGWATCH.CONF 5 2010-02-10 "GNU" "Linux Programmer's Manual" .SH NAME logwatch.conf, ignore.conf, override.conf - logwatch configuration files .SH DESCRIPTION .BR logwatch.conf - ( .BR /etc/logwatch/conf/logwatch.conf ) - can contain the local configuration options. The list of valid settings and their default values are in .BR /usr/share/logwatch/default.conf/logwatch.conf. .BR ignore.conf - ( .BR /etc/logwatch/conf/ignore.conf ) is the list of regular expressions. The set of logs described by this set is ignored by logwatch. .BR override.conf - ( .BR /etc/logwatch/conf/override.conf ) contains the settings which overrides the standard configuration of specific log files or services. The syntax is the same as in log/service files. .SH FILES .I /etc/logwatch/conf/logwatch.conf .I /etc/logwatch/conf/ignore.conf .I /etc/logwatch/conf/override.conf .I /usr/share/logwatch/default.conf/logwatch.conf .SH "SEE ALSO" .BR logwatch (8) logwatch-7.7/scripts/0000775000211400021140000000000014266616000015061 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/0000775000211400021140000000000014163646057016700 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/yum/0000775000211400021140000000000014163654043017504 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/yum/applydate0000664000211400021140000000336514163654043021421 0ustar logwatchlogwatch########################################################################## # $Id$ ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use POSIX qw(strftime); use Logwatch ':dates'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $time = time; # Two formats in use: SearchNewDate is for yum 2.1 and later, I believe my $SearchDate = TimeFilter('%m/%d/%y %H:%M:%S'); my $SearchNewDate = TimeFilter('%b %d %H:%M:%S'); if ( $Debug > 5 ) { print STDERR "DEBUG: Inside ApplyDate (yum)...\n"; print STDERR "DEBUG: Looking For: " . $SearchDate . " or " . $SearchNewDate . "\n"; } while (defined(my $ThisLine = )) { # Here we actually remove the dates, as well if ($ThisLine =~ s/^$SearchNewDate //o || $ThisLine =~ s/$SearchDate //o) { print $ThisLine; } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/autorpm/0000775000211400021140000000000014163652576020372 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/autorpm/applydate0000775000211400021140000000300614163646572022301 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use POSIX qw(strftime); use Logwatch ':dates'; my $time = time; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $SearchDate = TimeFilter('%a %b %e %H:..:.. [^ ]+ %Y - '); if ($Debug > 5) { print STDERR "DEBUG: Inside ApplyDate (autorpm)...\n"; print STDERR "DEBUG: Looking For: $SearchDate\n"; } while (defined(my $ThisLine = )) { if ($ThisLine =~ s/$SearchDate//o) { print $ThisLine; } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/cron/0000775000211400021140000000000014163652762017641 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/cron/applydate0000775000211400021140000000473514163652736021564 0ustar logwatchlogwatch #use strict; ########################################################################## # $Id$ ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use POSIX qw(strftime); use Logwatch ':dates'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; # SearchDate2 is for newer crond (i.e. RH7.X) my ($SearchDate, $SearchDate2, $ThisLine); my ($incount, $outcount) = (0, 0); my $time = time; my $hostname = $ENV{'HOSTNAME'}; my $OSname = $ENV{'OSname'}; $SearchDate = TimeFilter("%m/%d-%H:%M:%S"); $SearchDate2 = TimeFilter("%b %e %H:%M:%S"); if ($Debug > 5) { print STDERR "DEBUG: Inside ApplyDate (cron)...\n"; print STDERR "DEBUG: Looking For: $SearchDate or $SearchDate2\n"; } while (defined($ThisLine = )) { $incount++; #Solaris & IRIX CRON filter -mgt #Basically takes the cron format in /var/cron/log and makes it look like syslog if ( $OSname =~ /(SunOS|IRIX)/ ) { if ($ThisLine =~ m/^\>\s+CMD: (.+)$/o) { my $command = $1; my $nextline = ; my ($user, $ps, $datestamp) = $nextline =~ /^\>\s+(\w+) (\d+) . \w\w\w (\w\w\w\s+\d+ \d\d:\d\d:\d\d)/; $ThisLine = "$datestamp $hostname CROND[$ps]: ($user) CMD ($command)\n"; } } if ($ThisLine =~ m/^[^ ]+ \($SearchDate-[0123456789]+\) /o) { print $ThisLine; $outcount++; } elsif ($ThisLine =~ m/^$SearchDate2 [^ ]+ [\w\/]+\[\d+\]:/o) { print $ThisLine; $outcount++; } } if ($Debug > 5) { print STDERR "DEBUG: ApplyDate (cron): $incount Lines In, $outcount Lines Out\n"; } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/emerge/0000775000211400021140000000000014163653114020134 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/emerge/applydate0000664000211400021140000000543712670102057022047 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## # $Log: applydate,v $ # Revision 1.5 2008/03/24 23:31:26 kirk # added copyright/license notice to each script # # Revision 1.4 2007/02/16 04:38:13 bjorn # Check timestamp using proper "seconds since epoch" format, by Jason. # # Revision 1.3 2005/06/18 19:36:32 bjorn # Bug fix from Mike Frysinger for incorrect variable reference # # Revision 1.2 2005/05/03 19:33:39 bjorn # Added support for new date ranges # # Revision 1.1 2005/04/20 22:13:32 bjorn # Initial file by Matt Brown # ########################################################################## ########################################################################## # This was written by: Matt Brown, mdbrown at uwaterloo dot ca # # Please send all comments, suggestions, bug reports, # etc, to logwatch-devel@lists.sourceforge.net. ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### # Processes emerge logs to remove entries outside the desired date range use strict; use Logwatch ':dates'; use POSIX qw(strftime); my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; # Set the date we are looking for based on the desired date range my $SearchDate = TimeFilter('%Y %b %e %H:%M:%S'); if ($Debug > 5) { print STDERR "DEBUG: Inside applydate (emerge)...\n"; print STDERR "DEBUG: Looking For: $SearchDate\n"; } # Examine each line of the file, writing out only the lines that are within # the date range my $emergeTime; while (defined(my $line = )) { $line =~ /^(\d+):/; $emergeTime = strftime('%Y %b %e %H:%M:%S', localtime($1)); if ($Debug > 5) { print STDERR "DEBUG: converted time: $emergeTime\n"; } if ($emergeTime =~ /$SearchDate/) { print $line; } } # vi: shiftwidth=3 syntax=perl tabstop=3 et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/up2date/0000775000211400021140000000000014163653652020243 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/up2date/removeheaders0000775000211400021140000000234514163653642023025 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; while (defined(my $ThisLine = )) { $ThisLine =~ s/^\[... ... .. ..:..:.. ....\] up2date //; print $ThisLine; } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/up2date/applydate0000775000211400021140000000301414163653564022154 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use POSIX qw(strftime); use Logwatch ':dates'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $time = time; my $SearchDate = TimeFilter('%a %b %e %H:%M:%S %Y'); if ( $Debug > 5 ) { print STDERR "DEBUG: Inside ApplyDate (up2date)...\n"; print STDERR "DEBUG: Looking For: " . $SearchDate . "\n"; } while (defined(my $ThisLine = )) { if ($ThisLine =~ m/\[$SearchDate\]/o) { print $ThisLine; } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/xferlog/0000775000211400021140000000000014163653761020346 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/xferlog/removeheaders0000775000211400021140000000234714163653761023133 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; while (defined(my $ThisLine = )) { $ThisLine =~ s/^... ... .. ..:..:.. .... [0123456789]+ //; print $ThisLine; } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/xferlog/applydate0000775000211400021140000000301214163653712022247 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use POSIX qw(strftime); use Logwatch ':dates'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $time = time; my $SearchDate = TimeFilter('%b %e %H:%M:%S %Y'); if ( $Debug > 5 ) { print STDERR "DEBUG: Inside ApplyDate (xferlog)...\n"; print STDERR "DEBUG: Looking For: " . $SearchDate . "\n"; } while (defined(my $ThisLine = )) { if ($ThisLine =~ m/^... $SearchDate/o) { print $ThisLine; } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/samba/0000775000211400021140000000000014163653445017762 5ustar logwatchlogwatchlogwatch-7.7/scripts/logfiles/samba/removeheaders0000775000211400021140000000303514163653445022542 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## ######################################################## # This was written and is maintained by: # Luuk de Boer # # Please send all comments, suggestions, bug reports, # etc, to kirk@kaybee.org. ######################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; while (defined(my $ThisLine = )) { $ThisLine =~ s/^..\/..\/.. ..:..:.. //; $ThisLine =~ s/^\[....\/..\/.. ..:..:...+?\]\s*//; print $ThisLine; } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logfiles/samba/applydate0000775000211400021140000000446514163653365021705 0ustar logwatchlogwatch ########################################################################## # $Id$ ########################################################################## ######################################################## # This was written and is maintained by: # Luuk de Boer # # Please send all comments, suggestions, bug reports, # etc, to logwatch-devel@lists.sourceforge.net ######################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use POSIX qw(strftime); use Logwatch ':dates'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $time = time; my $SearchDate = TimeFilter('%m/%d/%y %H:%M:%S'); my $SearchDate2 = TimeFilter('%Y/%m/%d %H:%M:%S'); if ( $Debug > 5 ) { print STDERR "DEBUG: Inside ApplyDate (samba)...\n"; print STDERR "DEBUG: Looking For: $SearchDate or $SearchDate2\n"; } my $ThisLine = ; mainloop: while ($ThisLine) { if ($ThisLine =~ m/^$SearchDate /o) { print $ThisLine; $ThisLine = ; } elsif ($ThisLine =~ m/^\[$SearchDate2/o) { chomp($ThisLine); print $ThisLine; while ($ThisLine = ) { if ($ThisLine =~ m/^\[....\/..\/.. ..:..:../) { # Found next entry print "\n"; next mainloop; } else { chomp($ThisLine); print $ThisLine; } } print "\n"; } else { $ThisLine = ; } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.7/scripts/logwatch.pl0000775000211400021140000016605514266616000017246 0ustar logwatchlogwatch#!/usr/bin/perl -w use strict; ########################################################################## ########################################################################## # Most current version can always be found at: # https://sourceforge.net/p/logwatch/git/ci/master/tree/ # A tarball, perhaps not as current as the version listed above, can be # found at (after a slight delay): # https://sourceforge.net/projects/logwatch/files/latest/download ######################################################## # Specify version and build-date: my $Version = '7.7'; my $VDate = '07/22/22'; ####################################################### # Logwatch was originally written by: # Kirk Bauer # # Unless otherwise specified, Logwatch and all bundled filter scripts # are Copyright (c) Kirk Bauer and covered under the included MIT/X # Consortium license. # # Please file all bug reports, patches, and feature requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and disccusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ # ######################################################## ############################################################################ # ENV SETTINGS: # About the locale: some functions use locale information. In particular, # Logwatch makes use of strftime, which makes use of LC_TIME variable. Other # functions may also use locale information. # # Because the parsing must be in the same locale as the logged information, # and this appears to be "C", "POSIX", or "en_US", we set LC_ALL for # this and other scripts invoked by this script. We use "C" because it # is always (?) available, whereas POSIX or en_US may not. They all use # the same time formats and rely on the ASCII character set. # # Variables REAL_LANG and REAL_LC_ALL keep the original values for use by # scripts that need native language. $ENV{'REAL_LANG'}=$ENV{'LANG'} if $ENV{'LANG'}; $ENV{'REAL_LC_ALL'}=$ENV{'LC_ALL'} if $ENV{'LC_ALL'}; # Setting ENV for scripts invoked by this script. $ENV{'LC_ALL'} = "C"; # Using setlocale to set locale for this script. use POSIX qw(locale_h); setlocale(LC_ALL, "C"); my $BaseDir = "/usr/share/logwatch"; my $ConfigDir = "/etc/logwatch"; my $PerlVersion = "$^X"; ############################################################################# ############################################################################# # SET LIBS, GLOBALS, and DEFAULTS use Getopt::Long; use POSIX qw(uname); use File::Temp qw/ tempdir /; use Cwd; eval "use lib \"$BaseDir/lib\";"; eval "use Logwatch \':dates\'"; my (%Config, @ServiceList, @LogFileList, %ServiceData, %LogFileData); my (@TempLogDirs, @LogDirs); my (@AllShared, @AllLogFiles, @FileList); # These need to not be global variables one day my (@ReadConfigNames, @ReadConfigValues); # Default config here... $Config{'detail'} = 0; # if MAILTO is set in the environment, grab it, as it may be used by cron # or anacron if ($ENV{'MAILTO'}) { $Config{'mailto'} = $ENV{'MAILTO'}; } else { $Config{'mailto'} = "root"; } $Config{'mailfrom'} = "Logwatch"; $Config{'subject'} = ""; $Config{'filename'} = ""; $Config{'range'} = "yesterday"; $Config{'debug'} = 0; $Config{'archives'} = 1; $Config{'tmpdir'} = "/var/cache/logwatch"; $Config{'numeric'} = 0; $Config{'pathtocat'} = "cat"; $Config{'pathtozcat'} = "zcat"; $Config{'pathtobzcat'} = "bzcat"; $Config{'pathtoxzcat'} = "xzcat"; $Config{'output'} = "stdout"; #8.0 $Config{'format'} = "text"; #8.0 $Config{'encode'} = "none"; #8.0 $Config{'hostformat'} = "none"; #8.0 $Config{'html_wrap'} = 80; $Config{'suppress_ignores'} = 0; $Config{'hostlimit'} = ""; $Config{'appendvaradmtologdirs'} = 1; $Config{'appendvarlogtologdirs'} = 1; $Config{'appendcwdtologdirs'} = 0; if (-e "$ConfigDir/conf/html/header.html") { $Config{'html_header'} = "$ConfigDir/conf/html/header.html"; } elsif (-e "$BaseDir/dist.conf/html/header.html") { $Config{'html_header'} = "$BaseDir/dist.conf/html/header.html"; } else { $Config{'html_header'} = "$BaseDir/default.conf/html/header.html"; } if (-e "$ConfigDir/conf/html/footer.html") { $Config{'html_footer'} = "$ConfigDir/conf/html/footer.html"; } elsif (-e "$BaseDir/dist.conf/html/footer.html") { $Config{'html_footer'} = "$BaseDir/dist.conf/html/footer.html"; } else { $Config{'html_footer'} = "$BaseDir/default.conf/html/footer.html"; } #Added to create switches for different os options -mgt #Changed to POSIX to remove calls to uname and hostname my ($OSname, $hostname, $release, $version, $machine) = POSIX::uname(); $Config{'hostname'} = "$hostname"; my %wordsToInts = (yes => 1, no => 0, true => 1, false => 0, on => 1, off => 0, high => 10, med => 5, medium => 5, low => 0); ############################################################################# ############################################################################# #Load CONFIG, READ OPTIONS, make adjustments # Load main config file... if ($Config{'debug'} > 8) { print "\nDefault Config:\n"; &PrintConfig(); } &CleanVars(); # For each of the configuration sets (logwatch.conf here, and # logfiles,and services later), we do the following: # 1. read the different configuration files # 2. for each parameter, if it is cumulative, check if # it the special case empty string # 3. check to see if duplicate @ReadConfigNames = (); @ReadConfigValues = (); &ReadConfigFile ("$BaseDir/default.conf/logwatch.conf", ""); &ReadConfigFile ("$BaseDir/dist.conf/logwatch.conf", ""); &ReadConfigFile ("$ConfigDir/conf/logwatch.conf", ""); &ReadConfigFile ("$ConfigDir/conf/override.conf", "logwatch"); for (my $i = 0; $i <= $#ReadConfigNames; $i++) { if ($ReadConfigNames[$i] eq "logfile") { if ($ReadConfigValues[$i] eq "") { @LogFileList = (); } elsif (! grep(/^$ReadConfigValues[$i]$/, @LogFileList)) { push @LogFileList, $ReadConfigValues[$i]; } } elsif ($ReadConfigNames[$i] eq "service") { if ($ReadConfigValues[$i] eq "") { @ServiceList = (); } elsif (! grep(/^$ReadConfigValues[$i]$/, @ServiceList)) { push @ServiceList, $ReadConfigValues[$i]; } } elsif ($ReadConfigNames[$i] eq "logdir") { push @TempLogDirs, $ReadConfigValues[$i]; } else { $Config{$ReadConfigNames[$i]} = $ReadConfigValues[$i]; } } &CleanVars(); if ($Config{'debug'} > 8) { print "\nConfig After Config File:\n"; &PrintConfig(); } # Options time... my @TempLogFileList = (); my @TempServiceList = (); my $Help = 0; my $ShowVersion = 0; my ($tmp_mailto, $tmp_savefile); &GetOptions ("d|detail=s" => \$Config{'detail'}, "l|logfile=s@" => \@TempLogFileList, "logdir=s@" => \@TempLogDirs, "s|service=s@" => \@TempServiceList, "m|mailto=s" => \$tmp_mailto, "filename=s" => \$tmp_savefile, "a|archives" => \$Config{'archives'}, "debug=s" => \$Config{'debug'}, "r|range=s" => \$Config{'range'}, "n|numeric" => \$Config{'numeric'}, "h|help" => \$Help, "u|usage" => \$Help, "v|version" => \$ShowVersion, "hostname=s" => \$Config{'hostname'}, "o|output=s" => \$Config{'output'}, "f|format=s" => \$Config{'format'}, "e|encode=s" => \$Config{'encode'}, "hostformat=s" => \$Config{'hostformat'}, "hostlimit=s" => \$Config{'hostlimit'}, "html_wrap=s" => \$Config{'html_wrap'}, "subject=s" => \$Config{'subject'} ) or &Usage(); $Help and &Usage(); push @TempLogDirs, "/var/adm/" if $Config{'appendvaradmtologdirs'}; push @TempLogDirs, "/var/log/" if $Config{'appendvarlogtologdirs'}; # Empty string for LogDirs entry interpreted as `cwd`, but set # explicitly here for more readable debug output push @TempLogDirs, getcwd() if $Config{'appendcwdtologdirs'}; my %logdirs_seen; for my $logdir (@TempLogDirs) { # add trainling slash to directory if not there unless ($logdir =~ m=/$=) { $logdir .= "/"; } # remove duplicates if (! $logdirs_seen{$logdir}++) { push (@LogDirs, $logdir); } else { if ($Config{'debug'} > 2) { print "Removing duplicate LogDir declaration $logdir\n"; } } } #Catch option exceptions and extra logic here -mgt if ($Config{'range'} =~ /help/i) { &RangeHelpDM(); exit(0); } if ($ShowVersion) { print "Logwatch $Version (released $VDate)\n"; exit 0; } if ($tmp_mailto) { $Config{'mailto'} = $tmp_mailto; $Config{'output'} = "mail"; #8.0 } if ($tmp_savefile) { $Config{'filename'} = $tmp_savefile; $Config{'output'} = "file"; #8.0 } if ($Config{'hostformat'} eq "splitmail") { $Config{'output'} = "mail"; #8.0 #split hosts 1 long output stream #split hosts multiple output streams -mgt } &CleanVars(); #Init Output vars -mgt my $index_par=0; my @format = (250); my %out_body; my @reports = (); my $out_head =''; my $out_mime =''; my $out_reference =''; my $out_foot =''; #Eval wrapper for MIME::Base64. Perl 5.6.1 does not include it. #So Solaris 9 will break with out this. -mgt #8.0 Catch encode types here if ( $Config{'encode'} eq "base64" ) { eval "require MIME::Base64"; if ($@) { print STDERR "No MIME::Base64 installed; can not use --encode\n"; } else { import MIME::Base64; } } #Reset save file now if we are going ot use it and it exists -mgt if (($Config{'filename'} ne "") && (-e "$Config{'filename'}") ) { unlink "$Config{'filename'}"; } #Check fallback to stdout if output is mail and no mailto exists -mgt if ( ($Config{'output'} eq "mail") && ($Config{'mailto'} eq "") ) { $Config{'output'} = "stdout"; } if ($Config{'debug'} > 8) { print "\nCommand Line Parameters:\n Log File List:\n"; &PrintStdArray(@TempLogFileList); print "\n Service List:\n"; &PrintStdArray(@TempServiceList); print "\nConfig After Command Line Parsing:\n"; &PrintConfig(); } if ($#TempLogFileList > -1) { @LogFileList = @TempLogFileList; for (my $i = 0; $i <= $#LogFileList; $i++) { $LogFileList[$i] = lc($LogFileList[$i]); } @ServiceList = (); } if ($#TempServiceList > -1) { @ServiceList = @TempServiceList; for (my $i = 0; $i <= $#ServiceList; $i++) { $ServiceList[$i] = lc($ServiceList[$i]); } } if ( ($#ServiceList == -1) and ($#LogFileList == -1) ) { push @ServiceList, 'all'; } if ($Config{'debug'} > 5) { print "\nConfig After Everything:\n"; &PrintConfig(); } ############################################################################# # Find out what services are defined... my @TempAllServices = (); my @services = (); my (@CmdList, @CmdArgList, @Separators, $ThisFile, $count); foreach my $ServicesDir ("$BaseDir/default.conf", "$BaseDir/dist.conf", "$ConfigDir/conf") { if (-d "$ServicesDir/services") { opendir(SERVICESDIR, "$ServicesDir/services") or die "$ServicesDir $!"; while (defined($ThisFile = readdir(SERVICESDIR))) { if ((-f "$ServicesDir/services/$ThisFile") && (!grep (/^$ThisFile$/, @services)) && ($ThisFile =~ /\.conf$/)) { push @services, $ThisFile; } } closedir SERVICESDIR; } } foreach my $f (@services) { my $ThisService = lc $f; $ThisService =~ s/\.conf$//; push @TempAllServices, $ThisService; # @Separators tells us where each of the config files start, and # is used only for the commands (entries that start with '*') @ReadConfigNames = (); @ReadConfigValues = (); @Separators = (); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$BaseDir/default.conf/services/$f", ""); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$BaseDir/dist.conf/services/$f", ""); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$ConfigDir/conf/services/$f",""); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$ConfigDir/conf/override.conf", "services/$ThisService"); @CmdList = (); @CmdArgList = (); # set the default for DisplayOrder (0.5), which should be a fraction of any precision between 0 and 1 $ServiceData{$ThisService}{'displayorder'} = 0.5; for (my $i = 0; $i <= $#ReadConfigNames; $i++) { if (grep(/^$i$/, @Separators)) { $count = 0; } if ($ReadConfigNames[$i] eq 'logfile') { if ($ReadConfigValues[$i] eq "") { @{$ServiceData{$ThisService}{'logfiles'}} = (); } elsif (! grep(/^$ReadConfigValues[$i]$/, @{$ServiceData{$ThisService}{'logfiles'}})) { push @{$ServiceData{$ThisService}{'logfiles'}}, $ReadConfigValues[$i]; } } elsif ($ReadConfigNames[$i] =~ /^\*/) { if ($count == 0) { @CmdList = (); @CmdArgList = (); } $count++; push (@CmdList, $ReadConfigNames[$i]); push (@CmdArgList, $ReadConfigValues[$i]); } else { $ServiceData{$ThisService}{$ReadConfigNames[$i]} = $ReadConfigValues[$i]; } } for my $i (0..$#CmdList) { $ServiceData{$ThisService}{+sprintf("%03d-%s", $i, $CmdList[$i])} = $CmdArgList[$i]; } } my @AllServices = sort @TempAllServices; # Find out what logfiles are defined... my @logfiles = (); foreach my $LogfilesDir ("$BaseDir/default.conf", "$BaseDir/dist.conf", "$ConfigDir/conf") { if (-d "$LogfilesDir/logfiles") { opendir(LOGFILEDIR, "$LogfilesDir/logfiles") or die "$LogfilesDir $!"; while (defined($ThisFile = readdir(LOGFILEDIR))) { if ((-f "$LogfilesDir/logfiles/$ThisFile") && (!grep (/^$ThisFile$/, @logfiles))) { push @logfiles, $ThisFile; } } closedir LOGFILEDIR; } } for $ThisFile (@logfiles) { my $ThisLogFile = $ThisFile; if ($ThisLogFile =~ s/\.conf$//i) { push @AllLogFiles, $ThisLogFile; @ReadConfigNames = (); @ReadConfigValues = (); @Separators = (); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$BaseDir/default.conf/logfiles/$ThisFile", ""); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$BaseDir/dist.conf/logfiles/$ThisFile", ""); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$ConfigDir/conf/logfiles/$ThisFile", ""); push (@Separators, scalar(@ReadConfigNames)); &ReadConfigFile("$ConfigDir/conf/override.conf", "logfiles/$ThisLogFile"); @CmdList = (); @CmdArgList = (); @{$LogFileData{$ThisLogFile}{'logfiles'}} = (); @{$LogFileData{$ThisLogFile}{'archives'}} = (); # We use hashes to keep track of duplicates my (%logfile_seen, %archive_seen); for (my $i = 0; $i <= $#ReadConfigNames; $i++) { if (grep(/^$i$/, @Separators)) { $count = 0; } if ($ReadConfigNames[$i] eq "logfile") { my @TempLogFileList =(); #Lets try and find the logs -mgt if ($ReadConfigValues[$i] eq "") { @{$LogFileData{$ThisLogFile}{'logfiles'}} = (); %logfile_seen = (); } else { if ($ReadConfigValues[$i] !~ m=^/=) { foreach my $dir (@LogDirs) { # We glob to obtain filenames, and check existence push(@TempLogFileList, sort{ ($b =~ /(\d+)$/) <=> ($a =~ /(\d+)$/) || uc($a) cmp uc($b) }(grep {-e} glob($dir . $ReadConfigValues[$i]))); } } else { push(@TempLogFileList, sort{ ($b =~ /(\d+)$/) <=> ($a =~ /(\d+)$/) || uc($a) cmp uc($b) }(grep {-e} glob($ReadConfigValues[$i]))); } } # We remove duplicates. # Same applies to archives, in the next block, so we keep # %logfile_seen hash for later use. if ($Config{'debug'} > 2) { for my $logfile (grep {$logfile_seen{$_}} @TempLogFileList) { print "Removing duplicate LogFile file $logfile from"; print " $ThisFile configuration.\n"; } } push(@{$LogFileData{$ThisLogFile}{'logfiles'}}, grep { ! $logfile_seen{$_}++ } @TempLogFileList); } elsif (($ReadConfigNames[$i] eq "archive") && ( $Config{'archives'} == 1)) { my @TempLogFileList =(); if ($ReadConfigValues[$i] eq "") { @{$LogFileData{$ThisLogFile}{'archives'}} = (); %archive_seen = (); } else { # Test if absolute path if ($ReadConfigValues[$i] !~ m=^/=) { foreach my $dir (@LogDirs) { # We glob to obtain filenames, and check existence push(@TempLogFileList, sort{ ($b =~ /(\d+)$/) <=> ($a =~ /(\d+)$/) || uc($a) cmp uc($b) }(grep {-e} glob($dir . $ReadConfigValues[$i]))); } } else { foreach my $dir (@LogDirs) { push(@TempLogFileList, sort{ ($b =~ /(\d+)$/) <=> ($a =~ /(\d+)$/) || uc($a) cmp uc($b) }(grep {-e} glob($ReadConfigValues[$i]))); } } } # We remove duplicates. This time we also check # against the previous LogFile declarations. if ($Config{'debug'} > 2) { for my $logfile (grep {$archive_seen{$_}} @TempLogFileList) { print "Removing duplicate Archive file $logfile from"; print " $ThisFile configuration.\n"; } for my $logfile (grep {$logfile_seen{$_}} @TempLogFileList) { print "Archive file $logfile in both LogFile and Archive"; print " declarations in $ThisFile configuration.\n"; } } push(@{$LogFileData{$ThisLogFile}{'archives'}}, grep {! $archive_seen{$_}++ } grep { ! $logfile_seen{$_}++ } @TempLogFileList); } elsif ($ReadConfigNames[$i] =~ /^\*/) { if ($count == 0) { @CmdList = (); @CmdArgList = (); } $count++; push (@CmdList, $ReadConfigNames[$i]); push (@CmdArgList, $ReadConfigValues[$i]); } else { $LogFileData{$ThisLogFile}{$ReadConfigNames[$i]} = $ReadConfigValues[$i]; } } for my $i (0..$#CmdList) { $LogFileData{$ThisLogFile}{+sprintf("%03d-%s", $i, $CmdList[$i])} = $CmdArgList[$i]; } } } # Find out what shared functions are defined... opendir(SHAREDDIR, "$BaseDir/scripts/shared") or die "$BaseDir/scripts/shared/, $!\n"; while (defined($ThisFile = readdir(SHAREDDIR))) { unless (-d "$BaseDir/scripts/shared/$ThisFile") { push @AllShared, lc($ThisFile); } } closedir(SHAREDDIR); if ($Config{'debug'} > 5) { print "\nAll Services:\n"; &PrintStdArray(@AllServices); print "\nAll Log Files:\n"; &PrintStdArray(@AllLogFiles); print "\nAll Shared:\n"; &PrintStdArray(@AllShared); } ############################################################################# # Time to expand @ServiceList, using @LogFileList if defined... if ((scalar @ServiceList > 0) && (grep /^all$/i, @ServiceList)) { # This means we are doing *all* services ... but excluding some my %tmphash; foreach my $item (@AllServices) { $tmphash{lc $item} = ""; } foreach my $service (@ServiceList) { next if $service =~ /^all$/i; if ($service =~ /^\-(.+)$/) { my $offservice = lc $1; if (! grep (/^$offservice$/, @AllServices)) { die "Nonexistent service to disable: $offservice\n"; } if (exists $tmphash{$offservice}) { delete $tmphash{$offservice}; } } else { die "Wrong configuration entry for \"Service\", if \"All\" selected, only \"-\" items are allowed\n"; } } @ServiceList = (); foreach my $keys (keys %tmphash) { push @ServiceList, $keys; } @LogFileList = (); } else { my $ThisOne; while (defined($ThisOne = pop @LogFileList)) { unless ($LogFileData{$ThisOne}) { die "Logwatch is not configured to use logfile: $ThisOne\n"; } foreach my $ThisService (keys %ServiceData) { for (my $i = 0; $i <= $#{$ServiceData{$ThisService}{'logfiles'}}; $i++) { if ( $ServiceData{$ThisService}{'logfiles'}[$i] eq $ThisOne ) { push @ServiceList,$ThisService; } } } } @TempServiceList = sort @ServiceList; @ServiceList = (); my $LastOne = ""; while (defined($ThisOne = pop @TempServiceList)) { unless ( ($ThisOne eq $LastOne) or ($ThisOne eq 'all') or ($ThisOne =~ /^-/)) { unless ($ServiceData{$ThisOne}) { die "Logwatch does not know how to process service: $ThisOne\n"; } push @ServiceList, $ThisOne; } $LastOne = $ThisOne; } } # Now lets fill up @LogFileList again... foreach my $ServiceName (@ServiceList) { foreach my $LogName ( @{$ServiceData{$ServiceName}{'logfiles'} } ) { unless ( grep m/^$LogName$/, @LogFileList ) { push @LogFileList, $LogName; } } } if ($Config{'debug'} > 7) { print "\n\nAll Service Data:\n"; &PrintServiceData(); print "\nServices that will be processed:\n"; &PrintStdArray(@ServiceList); print "\n\n"; print "\n\nAll LogFile Data:\n"; &PrintLogFileData(); print "\nLogFiles that will be processed:\n"; &PrintStdArray(@LogFileList); print "\n\n"; } ############################################################################# # check for existence of previous logwatch directories opendir(TMPDIR, $Config{'tmpdir'}) or die "$Config{'tmpdir'} $!"; my @old_dirs = grep { /^logwatch\.\w{8}$/ && -d "$Config{'tmpdir'}/$_" } readdir(TMPDIR); if (@old_dirs) { print "You have old files in your logwatch tmpdir ($Config{'tmpdir'}):\n\t"; print join("\n\t", @old_dirs); print "\nThe directories listed above were most likely created by a\n"; print "logwatch run that failed to complete successfully. If so, you\n"; print "may delete these directories.\n\n"; } closedir(TMPDIR); if (!-w $Config{'tmpdir'}) { my $err_str = "You do not have permission to create a temporary directory"; $err_str .= " under $Config{'tmpdir'}."; if ($> !=0) { $err_str .= " You are not running as superuser."; } $err_str .= "\n"; die $err_str; } #Set very strict permissions because we deal with security logs umask 0177; #Making temp dir with File::Temp -mgt my $cleanup = 0; if ($Config{'debug'} < 100) { $cleanup = 1; } my $TempDir = tempdir( 'logwatch.XXXXXXXX', DIR => $Config{tmpdir}, CLEANUP => $cleanup ); if ($Config{'debug'}>7) { print "\nMade Temp Dir: " . $TempDir . " with tempdir\n"; } unless ($TempDir =~ m=/$=) { $TempDir .= "/"; } ############################################################################# # Set up the environment... $ENV{'LOGWATCH_DATE_RANGE'} = $Config{'range'}; $ENV{'LOGWATCH_GLOBAL_DETAIL'} = $Config{'detail'}; $ENV{'LOGWATCH_OUTPUT_TYPE'} = $Config{'output'}; #8.0 $ENV{'LOGWATCH_FORMAT_TYPE'} = $Config{'format'}; #8.0 $ENV{'LOGWATCH_DEBUG'} = $Config{'debug'}; $ENV{'LOGWATCH_TEMP_DIR'} = $TempDir; $ENV{'LOGWATCH_NUMERIC'} = $Config{'numeric'}; $ENV{'HOSTNAME'} = $Config{'hostname'}; $ENV{'OSname'} = $OSname; my $no_egrep = system("egrep -V > /dev/null 2>&1"); #split and splitmail also play with LOGWATCH_ONLY_HOSTNAME which is not shown by debug if ($Config{'hostlimit'}) { #Pass the list to ENV with out touching it $ENV{'LOGWATCH_ONLY_HOSTNAME'} = $Config{'hostlimit'}; } if ($Config{'debug'}>4) { foreach ('LOGWATCH_DATE_RANGE', 'LOGWATCH_GLOBAL_DETAIL', 'LOGWATCH_OUTPUT_TYPE', 'LOGWATCH_FORMAT_TYPE', 'LOGWATCH_TEMP_DIR', 'LOGWATCH_DEBUG', 'LOGWATCH_ONLY_HOSTNAME') { if ($ENV{$_}) { print "export $_='$ENV{$_}'\n"; } } } my $LibDir = "$BaseDir/lib"; if ($ENV{PERL5LIB}) { # User dirs should be able to override this setting $ENV{PERL5LIB} = "$ENV{PERL5LIB}:$LibDir"; } else { $ENV{PERL5LIB} = $LibDir; } ############################################################################# # Okay, now it is time to do pre-processing on all the logfiles... my @EnvList = (); my $LogFile; foreach $LogFile (@LogFileList) { next if ($LogFile eq 'none'); if (!defined($LogFileData{$LogFile}{'logfiles'})) { print "*** Error: There is no logfile defined. Do you have a $ConfigDir/conf/logfiles/" . $LogFile . ".conf file ?\n"; next; } @FileList = $TempDir . $LogFile . "-archive"; # Handle compressed log files using the archive codepath foreach my $lf (@{$LogFileData{$LogFile}{'logfiles'}}) { if ($lf =~ /\.(?:gz|bz2|xz)$/) { push @{$LogFileData{$LogFile}{'archives'}}, $lf; } else { push @FileList, $lf; } } my $DestFile = $TempDir . $LogFile . "-archive"; my $Archive; foreach $Archive (@{$LogFileData{$LogFile}{'archives'}}) { if ($Archive =~ /'/) { print "File $Archive has invalid embedded quotes. File ignored.\n"; next; } my $CheckTime; # We need to find out what's the earliest log we need my @time_t = TimeBuild(); if ($Config{'range'} eq 'all') { if ($Config{'archives'} == 0) { # range is 'all', but we don't get archive files $CheckTime = time; } else { # range is 'all', and we get all archive files $CheckTime = 0; } } elsif ($time_t[0]) { # range is something else, and we need to get one # day ahead. A day has 86400 seconds. (We double # that to deal with different timezones.) $CheckTime = $time_t[0] - 86400*2; } else { # range is wrong print STDERR "ERROR: Range \'$Config{'range'}\' not understood\n"; RangeHelpDM(); exit 1; } #Archives are cat'd without any filters then cat'd along with the normal log file my @FileStat = stat($Archive); if ($CheckTime <= ($FileStat[9])) { if (($Archive =~ m/gz$/) && (-f "$Archive") && (-s "$Archive")) { my $arguments = "'${Archive}' >> $DestFile"; system("$Config{'pathtozcat'} $arguments") == 0 or die "system '$Config{'pathtozcat'} $arguments' failed: $?" } elsif (($Archive =~ m/bz2$/) && (-f "$Archive") && (-s "$Archive")) { my $arguments = "'${Archive}' 2>/dev/null >> $DestFile"; system("$Config{'pathtobzcat'} $arguments") == 0 or die "system '$Config{'pathtobzcat'} $arguments' failed: $?" } elsif (($Archive =~ m/xz$/) && (-f "$Archive") && (-s "$Archive")) { my $arguments = "'${Archive}' 2>/dev/null >> $DestFile"; system("$Config{'pathtoxzcat'} $arguments") == 0 or die "system '$Config{'pathtoxzcat'} $arguments' failed: $?" } elsif ((-f "$Archive") && (-s "$Archive")) { my $arguments = "'${Archive}' >> $DestFile"; system("$Config{'pathtocat'} $arguments") == 0 or die "system '$Config{'pathtocat'} $arguments' failed: $?" } #End if/elsif existence } #End if $CheckTime } #End Archive my $FileText = ""; foreach my $ThisFile (@FileList) { #Existence check for files and character devices such as /dev/null next unless (-f $ThisFile || -c $ThisFile ); if ($ThisFile =~ /'/) { print "File $ThisFile has invalid embedded quotes. File ignored.\n"; next; } if (! -r $ThisFile) { print "File $ThisFile is not readable. Check permissions."; if ($> != 0) { print " You are not running as superuser."; } print "\n"; next; } #FIXME - We have a bug report for filenames with spaces, can be caught here needs test -mgt $FileText .= ("'" . $ThisFile . "' "); } #End foreach ThisFile # remove the ENV entries set by previous service foreach my $Parm (@EnvList) { delete $ENV{$Parm}; } @EnvList = (); my $FilterText = " "; if (-e "/usr/bin/iconv") { if (defined $Config{'charencoding'}) { my $from_encoding; if ($Config{'charencoding'}) { $from_encoding = "-f $Config{'charencoding'}"; } else { $from_encoding = ""; } $FilterText = " | iconv -c $from_encoding -t UTF-8 - "; } } foreach (sort keys %{$LogFileData{$LogFile}}) { my $cmd = $_; if ($cmd =~ s/^\d+-\*//) { if (-f "$ConfigDir/scripts/shared/$cmd") { $FilterText .= ("| $PerlVersion $ConfigDir/scripts/shared/$cmd '$LogFileData{$LogFile}{$_}'" ); } elsif (-f "$BaseDir/scripts/shared/$cmd") { $FilterText .= ("| $PerlVersion $BaseDir/scripts/shared/$cmd '$LogFileData{$LogFile}{$_}'" ); } else { die "Cannot find shared script $cmd\n"; } } elsif ($cmd =~ s/^\$//) { push @EnvList, $cmd; $ENV{$cmd} = $LogFileData{$LogFile}{$_}; if ($Config{'debug'}>4) { print "export $cmd='$LogFileData{$LogFile}{$_}'\n"; } } } #Hostlimit filter need to add ability to negate this use "NoHostFilter = Yes" in logfile like samba -mgt if ( ($Config{'hostlimit'}) && (!$LogFileData{$LogFile}{'nohostfilter'}) ) { #Pass the list to ENV with out touching it $ENV{'LOGWATCH_ONLY_HOSTNAME'} = $Config{'hostlimit'}; $FilterText .= ("| $PerlVersion $BaseDir/scripts/shared/onlyhost"); } if (opendir (LOGDIR, "$ConfigDir/scripts/logfiles/" . $LogFile)) { foreach (sort readdir(LOGDIR)) { unless ( -d "$ConfigDir/scripts/logfiles/$LogFile/$_") { $FilterText .= ("| $PerlVersion $ConfigDir/scripts/logfiles/$LogFile/$_"); } } closedir (LOGDIR); } if (opendir (LOGDIR, "$BaseDir/scripts/logfiles/" . $LogFile)) { foreach (sort readdir(LOGDIR)) { unless (( -d "$BaseDir/scripts/logfiles/$LogFile/$_") or # if in ConfigDir, then the ConfigDir version is used ( -f "$ConfigDir/scripts/logfiles/$LogFile/$_")) { $FilterText .= ("| $PerlVersion $BaseDir/scripts/logfiles/$LogFile/$_"); } } closedir (LOGDIR); } #Instead of trying to cat non-existent logs we test for it above -mgt if ($FileText) { my $Command = $FileText . $FilterText . ">" . $TempDir . $LogFile; if ($Config{'debug'}>4) { print "\nPreprocessing LogFile: " . $LogFile . "\n " . $Config{'pathtocat'} . " " . $Command . "\n"; } if ($LogFile !~ /^[-_\w\d]+$/) { print STDERR "Unexpected filename: [[$LogFile]]. Not used\n" } else { #System call does the log processing system("$Config{'pathtocat'} $Command") == 0 or die "system '$Config{'pathtocat'} $Command' failed: $?" } } } #populate the host lists if we're splitting hosts #It seems this is run after the file is parsed so it is done 2 times? #Can it be put inline with the above filters? my @hosts; if ($Config{'hostformat'} ne "none") { #8.0 my $newlogfile; my @logarray; opendir (LOGDIR,$TempDir) || die "Cannot open dir"; @logarray = readdir(LOGDIR); closedir (LOGDIR); my $ecpcmd = ("| $PerlVersion $BaseDir/scripts/shared/hostlist"); #Note hostlist and hosthash [which is never used] exist to build list of host names seen foreach $newlogfile (@logarray) { my $eeefile = ("$TempDir" . "$newlogfile"); if ((!(-d $eeefile)) && (!($eeefile =~ m/-archive/))) { system("$Config{'pathtocat'} $eeefile $ecpcmd") == 0 or die "system '$Config{'pathtocat'} $eeefile $ecpcmd' failed: $?" } } #read in the final host list open (HOSTFILE,"$TempDir/hostfile") || die $!; @hosts = ; close (HOSTFILE); chomp @hosts; #fixme check the sort? #@hosts = sort(@hosts); } ############################################################################# my $report_finish = "\n ###################### Logwatch End ######################### \n\n"; my $printing = ''; my $emailopen = ''; #################################################################### #Call Parse logs if ($Config{'hostformat'} ne "none") { my $Host; foreach $Host (@hosts) { $printing = ''; $ENV{'LOGWATCH_ONLY_HOSTNAME'} = $Host; $Config{'hostname'} = $Host; #resetting hostname here makes it appear in output header -mgt parselogs(); } # ECP } else { parselogs(); } #Close Filehandle is needed -mgt close(OUTFILE) unless ($Config{'output'} eq "stdout"); ############################################################################# exit(0); ############################################################################# #END MAIN ############################################################################# ###################################################################### #sub getInt #Notes: Called by CleanVars ###################################################################### sub getInt { my $word = shift; unless (defined($word)) { return $word; } my $tmpWord = lc $word; $tmpWord =~ s/\W//g; return $wordsToInts{$tmpWord} if (defined $wordsToInts{$tmpWord}); unless ($word =~ s/^"(.*)"$/$1/) { return lc $word; } return $word; } ###################################################################### #sub CleanVars #Notes: Called during #Load CONFIG, READ OPTIONS, make adjustments ###################################################################### sub CleanVars { foreach (keys %Config) { unless (defined $Config{$_} and # For the following config keys, do not make any changes to value ($_ =~ /^(hostname|filename|mailto|logdir|hostlimit|mailer)$/ )) { $Config{$_} = getInt($Config{$_}); } } } ###################################################################### #sub PrintStdArray # ###################################################################### sub PrintStdArray (@) { my @ThisArray = @_; my $i; for ($i=0;$i<=$#ThisArray;$i++) { print "[" . $i . "] = " . $ThisArray[$i] . "\n"; } } ###################################################################### #sub PrintConfig # ###################################################################### sub PrintConfig () { # for debugging, print out config... foreach (sort keys %Config) { print $_ . ' -> ' . $Config{$_} . "\n"; } print "Logdirs List:\n"; &PrintStdArray(@LogDirs); print "Service List:\n"; &PrintStdArray(@ServiceList); print "\n"; print "LogFile List:\n"; &PrintStdArray(@LogFileList); print "\n\n"; } ###################################################################### #sub PrintServiceData # ###################################################################### # for debugging... sub PrintServiceData () { my ($ThisKey1,$ThisKey2,$i); foreach $ThisKey1 (keys %ServiceData) { print "\nService Name: " . $ThisKey1 . "\n"; foreach $ThisKey2 (keys %{$ServiceData{$ThisKey1}}) { next unless ($ThisKey2 =~ /^\d+-/); print " $ThisKey2 = $ServiceData{$ThisKey1}{$ThisKey2}\n"; } for ($i=0;$i<=$#{$ServiceData{$ThisKey1}{'logfiles'}};$i++) { print " Logfile = " . $ServiceData{$ThisKey1}{'logfiles'}[$i] . "\n"; } } } ###################################################################### #sub PrintLogFileData # ###################################################################### # for debugging... sub PrintLogFileData () { my ($ThisKey1,$ThisKey2,$i); foreach $ThisKey1 (keys %LogFileData) { print "\nLogfile Name: " . $ThisKey1 . "\n"; foreach $ThisKey2 (keys %{$LogFileData{$ThisKey1}}) { next unless ($ThisKey2 =~ /^\d+-/); print " $ThisKey2 = $LogFileData{$ThisKey1}{$ThisKey2}\n"; } for ($i=0;$i<=$#{$LogFileData{$ThisKey1}{'logfiles'}};$i++) { print " Logfile = " . $LogFileData{$ThisKey1}{'logfiles'}[$i] . "\n"; } for ($i=0;$i<=$#{$LogFileData{$ThisKey1}{'archives'}};$i++) { print " Archive = " . $LogFileData{$ThisKey1}{'archives'}[$i] . "\n"; } if ($LogFileData{$ThisKey1}{'nohostfilter'}) { print " NoHostFilter = " . $LogFileData{$ThisKey1}{'nohostfilter'} . "\n"; } } } ###################################################################### #sub ReadConfigFile # ###################################################################### sub ReadConfigFile { my $FileName = $_[0]; my $Prefix = $_[1]; if ( ! -f $FileName ) { return(0); } if ($Config{'debug'} > 5) { print "ReadConfigFile: Opening " . $FileName . "\n"; } open (READCONFFILE, $FileName) or die "Cannot open file $FileName: $!\n"; my $line; while ($line = ) { if ($Config{'debug'} > 9) { print "ReadConfigFile: Read Line: " . $line; } $line =~ s/\#.*\\\s*$/\\/; $line =~ s/\#.*$//; next if ($line =~ /^\s*$/); if ($Prefix) { next if ($line !~ m/\Q$Prefix:\E/); $line =~ s/\Q$Prefix:\E//; } if ($line =~ s/\\\s*$//) { $line .= ; redo unless eof(READCONFFILE); } my ($name, $value) = split /=/, $line, 2; $name =~ s/^\s+//; $name =~ s/\s+$//; if ($value) { $value =~ s/^\s+//; $value =~ s/\s+$//; } else { $value = ''; } push @ReadConfigNames, lc $name; push @ReadConfigValues, getInt $value; if ($Config{'debug'} > 7) { print "ReadConfigFile: Name=" . $name . ", Value=" . $value . "\n"; } } close READCONFFILE; } ######################################################################### #sub Usage # ######################################################################### sub Usage () { # Show usage for this program print "\nUsage: $0 [--detail ] [--logfile ] [--output ]\n" . " [--format ] [--encode ] [--numeric]\n" . " [--mailto ] [--archives] [--range ] [--debug ]\n" . " [--filename ] [--help|--usage] [--version] [--service ]\n" . " [--hostformat ] [--hostlimit ] [--html_wrap ]\n\n"; print "--detail : Report Detail Level - High, Med, Low or any #.\n"; print "--logfile : *Name of a logfile definition to report on.\n"; print "--logdir : Name of default directory where logs are stored.\n"; print "--service : *Name of a service definition to report on.\n"; print "--output : Report Output - stdout [default], mail, file.\n"; #8.0 print "--format : Report Format - text [default], html.\n"; #8.0 print "--encode : Encoding to use - none [default], base64, 7bit, 8bit [same as 'none'].\n"; #8.0 print "--mailto : Mail report to .\n"; print "--archives: Use archived log files too.\n"; print "--filename : Used to specify they filename to save to. --filename [Forces output to file].\n"; print "--range : Date range: Yesterday, Today, All, Help\n"; print " where help will describe additional options\n"; print "--numeric: Display addresses numerically rather than symbolically and numerically\n"; print " (saves a nameserver address-to-name lookup).\n"; print "--debug : Debug Level - High, Med, Low or any #.\n"; print "--hostformat: Host Based Report Options - none [default], split, splitmail.\n"; #8.0 print "--hostlimit: Limit report to hostname - host1,host2.\n"; #8.0 print "--hostname: overwrites hostname\n"; print "--html_wrap : Default is 80.\n"; print "--version: Displays current version.\n"; print "--help: This message.\n"; print "--usage: Same as --help.\n"; print "* = Switch can be specified multiple times...\n\n"; exit (99); } ############################################################################ #END sub Usage ############################################################################# ############################################################################# #sub initprint # ############################################################################# sub initprint { return if $printing; my $OStitle; $OStitle = $OSname; $OStitle = "Solaris" if ($OSname eq "SunOS" && $release >= 2); if ($Config{'output'} eq "stdout") { #8.0 start with others? *OUTFILE = *STDOUT; } elsif ($Config{'output'} eq "file") { open(OUTFILE,">>" . $Config{'filename'}) or die "Can't open output file: $Config{'filename'} $!\n"; } else { #fixme mailto if (($Config{'hostformat'} eq "splitmail") || ($emailopen eq "")) { #Use mailer = in logwatch.conf to set options. Default should be "sendmail -t" #In theory this should be able to handle many different mailers. I might need to add #some filter code on $Config{'mailer'} to make it more robust. -mgt open(OUTFILE,"|$Config{'mailer'}") or die "Can't execute $Config{'mailer'}: $!\n"; my $mailto = $Config{"mailto_$Config{'hostname'}"}; $mailto = $Config{'mailto'} unless $mailto; for my $to (split(/ /, $mailto)) { print OUTFILE "To: $to\n"; } print OUTFILE "From: $Config{'mailfrom'}\n"; #If $Config{'subject'} exists lets use it. #This does not allow for variable expansion as the default below does -mgt if ($Config{'subject'}) { print OUTFILE "Subject: $Config{'subject'}\n"; } else { print OUTFILE "Subject: Logwatch for $Config{'hostname'} (${OStitle})\n"; } #Add headers to recognize automatically generated email print OUTFILE "Auto-Submitted: auto-generated\n"; print OUTFILE "Precedence: bulk\n"; #Add MIME $out_mime = "MIME-Version: 1.0\n"; #Config{encode} switch if ( $Config{'encode'} eq "base64" ) { $out_mime .= "Content-transfer-encoding: base64\n"; } elsif ( $Config{'encode'} eq "7bit" ) { $out_mime .= "Content-Transfer-Encoding: 7bit\n"; } else { $out_mime .= "Content-Transfer-Encoding: 8bit\n"; } #Config{output} html if ( $Config{'format'} eq "html" ) { $out_mime .= "Content-Type: text/html; charset=\"UTF-8\"\n\n"; } else { $out_mime .= "Content-Type: text/plain; charset=\"UTF-8\"\n\n"; } if ($Config{'hostformat'} eq "split") { #8.0 check hostlimit also? or ne none? print OUTFILE "Reporting on hosts: @hosts\n"; } $emailopen = 'y'; } #End if hostformat || emailopen } #End if printing/save/else $printing = 'y'; # simple parse of the dates my $simple_timematch = &TimeFilter(" %Y-%b-%d %Hh %Mm %Ss "); my @simple_range = split(/\|/, $simple_timematch); if ($#simple_range > 1) { # delete all array entries, except first and last splice(@simple_range, 1, $#simple_range-1); } for (my $range_index=0; $range_index<$#simple_range+1; $range_index++) { $simple_range[$range_index] =~ s/\.\.[hms]//g; $simple_range[$range_index] =~ s/\.//g; $simple_range[$range_index] =~ tr/--//s; $simple_range[$range_index] =~ s/ -|- //; $simple_range[$range_index] =~ tr/ //s; } my $print_range = join("/",@simple_range); $index_par++; if ( $Config{'format'} eq "html" ) { &output( $index_par, "LOGWATCH Summary" . (($Config{'hostformat'} ne "none") ? ": $Config{'hostname'}" : ""), "start"); &output( $index_par, " Logwatch Version: $Version ($VDate)\n", "line"); } else { &output( $index_par, "\n ################### Logwatch $Version ($VDate) #################### \n", "line"); } &output( $index_par, " Processing Initiated: " . localtime(time) . "\n", "line"); &output( $index_par, " Date Range Processed: $Config{'range'}\n", "line"); &output( $index_par, " $print_range\n", "line") if ($Config{'range'} ne 'all'); &output( $index_par, " Period is " . &GetPeriod() . ".\n", "line") if ($Config{'range'} ne 'all'); &output( $index_par, " Detail Level of Output: $Config{'detail'}\n", "line"); &output( $index_par, " Type of Output/Format: $Config{'output'} / $Config{'format'}\n", "line"); &output( $index_par, " Logfiles for Host: $Config{'hostname'}\n", "line"); if ( $Config{'hostlimit'} ) { &output( $index_par, " Hosts limited to: $Config{'hostlimit'}\n", "line"); } if ( $Config{'format'} eq "html" ) { &output( $index_par, "\n", "stop"); } else { &output( $index_par, "################################################################## \n", "line"); } } #################################################################### #END sub initprint #################################################################### ################################################################### #sub parselogs # ################################################################### sub parselogs { my $Service; #Load our ignore file order is [assume normal install] /etc/conf, /usr/share/logwatch/dist.conf and then default.conf -mgt my @IGNORE; if ( -e "$ConfigDir/conf/ignore.conf") { open( IGNORE, "$ConfigDir/conf/ignore.conf" ) or return undef; @IGNORE = grep {!/(^#|^\s+$)/} ; close IGNORE; } elsif ( -e "$BaseDir/dist.conf/ignore.conf") { open( IGNORE, "$BaseDir/dist.conf/ignore.conf" ) or return undef; @IGNORE = grep {!/(^#|^\s+$)/} ; close IGNORE; } elsif ( -e "$BaseDir/default.conf/ignore.conf") { open( IGNORE, "$BaseDir/default.conf/ignore.conf" ) or return undef; @IGNORE = grep {!/(^#|^\s+$)/} ; close IGNORE; } my @EnvList = (); # first sort alphabetically, and then based on DisplayOrder foreach $Service ( sort {$ServiceData{$a}{'displayorder'} <=> $ServiceData{$b}{'displayorder'} } (sort @ServiceList)) { my $Ignored = 0; $ENV{'PRINTING'} = $printing; if (defined $ServiceData{$Service}{'detail'}) { $ENV{'LOGWATCH_DETAIL_LEVEL'} = $ServiceData{$Service}{'detail'}; } else { $ENV{'LOGWATCH_DETAIL_LEVEL'} = $ENV{'LOGWATCH_GLOBAL_DETAIL'}; } @FileList = @{$ServiceData{$Service}{'logfiles'}}; my $FileText = ""; foreach $ThisFile (@FileList) { if (-s $TempDir . $ThisFile) { $FileText .= ( $TempDir . $ThisFile . " " ); } } # remove the ENV entries set by previous service foreach my $Parm (@EnvList) { delete $ENV{$Parm}; } @EnvList = (); my $FilterText = ""; foreach (sort keys %{$ServiceData{$Service}}) { my $cmd = $_; if ($cmd =~ s/^\d+-\*//) { if (-f "$ConfigDir/scripts/shared/$cmd") { $FilterText .= ("$PerlVersion $ConfigDir/scripts/shared/$cmd '$ServiceData{$Service}{$_}' | " ); } elsif (-f "$BaseDir/scripts/shared/$cmd") { $FilterText .= ("$PerlVersion $BaseDir/scripts/shared/$cmd '$ServiceData{$Service}{$_}' | " ); } else { die "Cannot find shared script $cmd\n"; } } elsif ($cmd =~ s/^\$//) { $ENV{$cmd} = $ServiceData{$Service}{$_}; push @EnvList, $cmd; if ($Config{'debug'}>4) { print "export $cmd='$ServiceData{$Service}{$_}'\n"; } } } # set env variables LOGWATCH_mumble_LIST push @EnvList, 'LOGWATCH_LOGFILE_LIST'; push @EnvList, 'LOGWATCH_ARCHIVE_LIST'; $ENV{'LOGWATCH_LOGFILE_LIST'} = ''; $ENV{'LOGWATCH_ARCHIVE_LIST'} = ''; foreach my $LogGroup (@FileList) { foreach my $log (@{$LogFileData{$LogGroup}{'logfiles'}}) { $ENV{'LOGWATCH_LOGFILE_LIST'} .= $log . " "; } foreach my $archive (@{$LogFileData{$LogGroup}{'archives'}}) { $ENV{'LOGWATCH_ARCHIVE_LIST'} .= $archive . " "; } } if ($Config{'debug'}>4) { print "\nexport LOGWATCH_LOGFILE_LIST='$ENV{LOGWATCH_LOGFILE_LIST}'"; print "\nexport LOGWATCH_ARCHIVE_LIST='$ENV{LOGWATCH_ARCHIVE_LIST}'"; } # ECP - insert the host stripping now my $HostStrip = " "; if ($Config{'hostformat'} ne "none") { #8.0 ############################################### # onlyhost reads $ENV{'LOGWATCH_ONLY_HOSTNAME'} and uses it to try and match # based on $line =~ m/^... .. ..:..:.. $hostname\b/io ############################################### $HostStrip = "$PerlVersion $BaseDir/scripts/shared/onlyhost"; } my $ServiceExec = "$BaseDir/scripts/services/$Service"; if (-f "$ConfigDir/scripts/services/$Service") { $ServiceExec = "$ConfigDir/scripts/services/$Service"; } else { $ServiceExec = "$BaseDir/scripts/services/$Service"; } if (-f $ServiceExec ) { #If shell= was set in service.conf we will use it if ($ServiceData{$Service}{shell}) { my $shelltest = $ServiceData{$Service}{shell}; $shelltest =~ s/([\w\/]+).*/$1/; if (-e "$shelltest") { $FilterText .= "$ServiceData{$Service}{shell} $ServiceExec"; } else { die "Can't use $ServiceData{$Service}{shell} for $ServiceExec"; } } else { $FilterText .= "$PerlVersion $ServiceExec"; } #End if shell } else { die "Can't open: " . $ServiceExec; } my $Command = ''; if (! @FileList) { output(1, "\n Warning: LogFile of service $ServiceData{$Service}{title} is not defined.\n", "line"); } else { if ($FileList[0] eq 'none') { $Command = " $FilterText 2>&1 "; } elsif ($FileText) { $Command = " ( $Config{'pathtocat'} $FileText| " ; if ($ServiceData{$Service}{pre_ignore}) { if ($no_egrep) { die "No egrep executable found, which is required when\n" . "using the Pre_Ignore variable in configuration \n" . "file ${Service}.conf\n"; } else { $Command .= "egrep -v \"$ServiceData{$Service}{pre_ignore}\" | "; } } if ($HostStrip ne " ") { $Command .= "$HostStrip | "; } $Command .= "$FilterText) 2>&1 "; } } if ($Command) { if ($Config{'debug'}>4) { print "\nProcessing Service: " . $Service . "\n" . $Command . "\n"; } open (TESTFILE,$Command . " |"); my $ThisLine; my $has_output = 0; LINE: while (defined ($ThisLine = )) { next LINE if ((not $printing) and $ThisLine =~ /^\s*$/); IGNORE: for my $ignore_filter (@IGNORE) { chomp $ignore_filter; if ($ThisLine =~ m/$ignore_filter/) { $Ignored++; next LINE; } } &initprint(); if (($has_output == 0) and ($ServiceData{$Service}{'title'})) { $index_par++; &output($index_par, $ServiceData{$Service}{'title'}, "start" ); my $BeginVar; if ($ENV{'LOGWATCH_GLOBAL_DETAIL'} == $ENV{'LOGWATCH_DETAIL_LEVEL'}) { $BeginVar = "Begin"; } else { $BeginVar = "Begin (detail=" . $ENV{'LOGWATCH_DETAIL_LEVEL'} . ")"; } if ( $Config{'format'} eq "html" ) { #BODY #&output( $index_par, "\n

$ServiceData{$Service}{'title'}

\n", "header"); } else { &output( $index_par, "\n --------------------- $ServiceData{$Service}{'title'} $BeginVar ------------------------ \n\n", "line"); } $has_output = 1; } &output( $index_par, $ThisLine, "line"); } close (TESTFILE); if ($has_output and $ServiceData{$Service}{'title'}) { if ( $Config{'format'} eq "html" ) { if ( ($Ignored > 0) && ($Config{'suppress_ignores'} == 0) ) { &output( $index_par, "\n $Ignored Ignored Lines\n", "header"); }; #&output( $index_par, "\n

$ServiceData{$Service}{'title'} End

\n", "header"); } else { if ( ($Ignored > 0) && ($Config{'suppress_ignores'} == 0) ) { &output( $index_par, "\n $Ignored Ignored Lines\n", "line"); }; &output( $index_par, "\n ---------------------- $ServiceData{$Service}{'title'} End ------------------------- \n\n", "line"); } &output( $index_par, "\n", "stop"); } } } #HTML should be external to logwatch.pl -mgt #These are steps only needed for HTML output if ( $Config{'format'} eq "html" ) { #HEADER #Setup temp Variables to swap my %HTML_var; $HTML_var{Version} = "$Version"; $HTML_var{VDate} = "$VDate"; #open template this needs to allow directory override like the rest of the confs open(HEADER, "$Config{html_header}") || die "Can not open HTML Header at $Config{html_header}: $!\n"; my @header =
; close HEADER; #Expand variables... There must be a better way -mgt for my $header_line (@header) { $header_line =~ s/\$([\w\_\-\{\}\[\]]+)/$HTML_var{$1}/g; $out_head .= $header_line; } #FOOTER #open template this needs to allow directory override like the rest of the confs open(FOOTER, "$Config{html_footer}") || die "Can not open HTML Footer at $Config{html_header}: $!\n"; my @footer =