program collectUAs; {$ifdef FPC} {$mode objfpc} {$endif} {$H+} uses SysUtils, Classes; var sr: TSearchRec; i, f, o, ua: integer; sPath, line, s: string; fields, useragents: TStringList; begin if (ParamStr(1)='') or not DirectoryExists(ParamStr(1)) then begin WriteLn('Collect UserAgent Strings'); Writeln('Usage: collectUAs [pathToTheLogfileFolder]'); end else begin sPath := ParamStr(1); fields := TStringlist.Create(); try fields.Delimiter := ' '; fields.QuoteChar := #$0; // create the storage useragents := TStringlist.Create(); try if FindFirst(sPath + '*.log', faAnyFile, sr) = 0 then repeat // loop through the logfiles with TStringList.Create() do try LoadFromFile(sPath + sr.Name); for i:=0 to Count-1 do begin // loop through the lines of the logfile line := Strings[i]; if (trim(line)<>'') then // jump over empty lines begin if (pos('#Fields:', line)=1) then // read the field list with fields do try DelimitedText := line; for f:=0 to Count-1 do // for this case we need only the user-agenr if Strings[f]='cs(User-Agent)' then begin ua := f-1; break; end; f := Count-1; finally clear; end else if not (pos('#',line)=1) then // ignore all other comments // get only the Values with fields do try // replace possible errors (an empty field) DelimitedText := StringReplace(line, ' ', ' - ', [rfReplaceAll]); // only check the lines that have the right number of fields if (Count = f) then begin // get the User-Agent Value s := Strings[ua]; // IIS replaces a space by a plus, replace "+" by " " s := StringReplace(s, '++', ' '#9, [rfReplaceAll]); s := StringReplace(s, '+(+http', ' ('#9'http', [rfReplaceAll]); s := StringReplace(s, '+', ' ', [rfReplaceAll]); s := StringReplace(s, #9, '+', [rfReplaceAll]); // check if user-agent is already in the storage o := useragents.IndexOf(s); if o = -1 then begin // if not, add the new user-agent writeln(s); useragents.Add(s); end; end; finally clear; end; end; end; finally Free; end; // save useragent.txt in local path useragents.SaveToFile(ExtractFilePath(ParamStr(0)) + 'useragents.txt'); until FindNext(sr) <> 0; FindClose(sr); finally useragents.Free; end; finally fields.Free; end; end; end.