@@ -66,12 +66,11 @@ class IISLogsPlugin(WebserverPlugin):
6666
6767 APPLICATION_HOST_CONFIG = "%windir%/system32/inetsrv/config/applicationHost.config"
6868
69- DEFAULT_LOG_PATHS = (
70- "%windir%\\ System32\\ LogFiles\\ W3SVC*\\ *.log" ,
71- "sysvol\\ Windows.old\\ Windows\\ System32\\ LogFiles\\ W3SVC*\\ *.log" ,
72- "sysvol\\ inetpub\\ logs\\ LogFiles\\ *.log" ,
73- "sysvol\\ inetpub\\ logs\\ LogFiles\\ W3SVC*\\ *.log" ,
74- "sysvol\\ Resources\\ Directory\\ *\\ LogFiles\\ Web\\ W3SVC*\\ *.log" ,
69+ DEFAULT_LOG_DIRS = (
70+ "%windir%\\ System32\\ LogFiles\\ W3SVC*" ,
71+ "sysvol\\ Windows.old\\ Windows\\ System32\\ LogFiles\\ W3SVC*" ,
72+ "sysvol\\ inetpub\\ logs\\ LogFiles" ,
73+ "sysvol\\ Resources\\ Directory\\ *\\ LogFiles\\ Web\\ W3SVC*" ,
7574 )
7675
7776 __namespace__ = "iis"
@@ -91,28 +90,12 @@ def log_dirs(self) -> dict[str, set[Path]]:
9190 if (sysvol_files := self .target .fs .path ("sysvol/files" )).exists ():
9291 dirs ["auto" ].add (sysvol_files )
9392
94- try :
95- xml_data = ElementTree .fromstring (self .config .read_bytes (), forbid_dtd = True )
96- for log_file_element in xml_data .findall ("*/sites/*/logFile" ):
97- log_format = log_file_element .get ("logFormat" ) or "W3C"
98- if log_dir := log_file_element .get ("directory" ):
99- if log_format not in dirs :
100- self .target .log .warning ("Unsupported log format %s, skipping %s" , log_format , log_dir )
101- continue
102- dirs [log_format ].add (self .target .resolve (log_dir ))
103-
104- except (ElementTree .ParseError , FileNotFoundError ) as e :
105- self .target .log .warning ("Error while parsing %s" , self .config )
106- self .target .log .debug ("" , exc_info = e )
93+ if self .config .exists ():
94+ self ._read_config_log_paths (dirs )
10795
108- for log_path in self .DEFAULT_LOG_PATHS :
109- try :
110- # later on we use */*.log to collect the files, so we need to move up 2 levels
111- log_path = self .target .expand_env (log_path )
112- log_dir = self .target .fs .path (log_path ).parents [1 ]
113- except IndexError :
114- self .target .log .info ("Incompatible path found: %s" , log_path )
115- continue
96+ for log_dir in self .DEFAULT_LOG_DIRS :
97+ log_dir = self .target .expand_env (log_dir )
98+ log_dir = self .target .fs .path (log_dir )
11699
117100 if not has_glob_magic (str (log_dir )) and log_dir .exists ():
118101 dirs ["auto" ].add (log_dir )
@@ -132,6 +115,21 @@ def _get_paths(self) -> Iterator[Path]:
132115 def _get_auxiliary_paths (self ) -> Iterator [Path ]:
133116 yield from {self .config }
134117
118+ def _read_config_log_paths (self , dirs : dict [str , set [str ]]) -> None :
119+ try :
120+ xml_data = ElementTree .fromstring (self .config .read_bytes (), forbid_dtd = True )
121+ for log_file_element in xml_data .findall ("*/sites/*/logFile" ):
122+ log_format = log_file_element .get ("logFormat" ) or "W3C"
123+ if log_dir := log_file_element .get ("directory" ):
124+ if log_format not in dirs :
125+ self .target .log .warning ("Unsupported log format %s, skipping %s" , log_format , log_dir )
126+ continue
127+ dirs [log_format ].add (self .target .resolve (log_dir ))
128+
129+ except (ElementTree .ParseError , FileNotFoundError ) as e :
130+ self .target .log .warning ("Error while parsing %s" , self .config )
131+ self .target .log .debug ("" , exc_info = e )
132+
135133 @export (record = BasicRecordDescriptor )
136134 def logs (self ) -> Iterator [TargetRecordDescriptor ]:
137135 """Return contents of IIS (v7 and above) log files.
@@ -142,22 +140,28 @@ def logs(self) -> Iterator[TargetRecordDescriptor]:
142140 Supported log formats: IIS, W3C.
143141 """
144142
143+ # We handle direct files here because _get_paths cannot select (filter) on the type of logfile.
144+ if self .target .is_direct :
145+ for log_file in self .get_paths ():
146+ yield from parse_autodetect_format_log (self .target , log_file )
147+ # If we use the direct loader, there are no other files available.
148+ return
149+
145150 parsers = {
146151 "W3C" : parse_w3c_format_log ,
147152 "IIS" : parse_iis_format_log ,
148153 "auto" : parse_autodetect_format_log ,
149154 }
150155
151- for format in ( "IIS" , "W3C" , "auto" ):
156+ for format , parser in parsers . items ( ):
152157 for log_dir in self .log_dirs .get (format , ()):
153- for log_file in log_dir .glob ( "*/ *.log" ):
158+ for log_file in log_dir .rglob ( " *.log" ):
154159 self .target .log .info ("Processing IIS log file %s in %s format" , log_file , format )
155- yield from parsers [format ](self .target , log_file )
156-
157- # We handle direct files here because _get_paths cannot select (filter) on the type of logfile.
158- if self .target .is_direct :
159- for log_file in self .get_paths ():
160- yield from parse_autodetect_format_log (self .target , log_file )
160+ try :
161+ yield from parser (self .target , log_file )
162+ except Exception as e :
163+ self .target .log .error ("Issue processing log file %s in %s format" , log_file , format ) # noqa TRY400
164+ self .target .log .debug ("" , exc_info = e )
161165
162166 @export (record = WebserverAccessLogRecord )
163167 def access (self ) -> Iterator [WebserverAccessLogRecord ]:
@@ -245,6 +249,7 @@ def parse_w3c_format_log(target: Target, path: Path) -> Iterator[TargetRecordDes
245249
246250 if not record_descriptor :
247251 target .log .warning ("Comment line with the fields defined should come before the values, skipping: %r" , line )
252+ continue
248253
249254 raw = replace_dash_with_none (dict (zip (fields , values , strict = False )))
250255
0 commit comments