2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/readlog.h"
30 #include "include/filelist.h"
32 #define REPORT_EVERY_X_LINES 5000
33 #define MAX_OPEN_USER_FILES 10
37 struct userfilestruct
*next
;
38 struct userinfostruct
*user
;
42 enum ExcludeReasonEnum
44 //! User name too long.
46 //! Squid logged an incomplete query received from the client.
48 //! Log file turned over.
50 //! Excluded by exclude_string from sarg.conf.
52 //! Unknown input log file format.
54 //! Line to be ignored from the input log file.
56 //! Entry not withing the requested date range.
62 //! User is not in the include_users list.
64 //! HTTP code excluded by exclude_code file.
66 //! Invalid character found in user name.
70 //! Not the IP address requested with -a.
72 //! URL excluded by -c or exclude_hosts.
74 //! Entry time outside of requested hour range.
76 //! Not the URL requested by -s.
80 //! Not the user requested by -u.
84 //! User ignored by exclude_users
87 ER_Last
//!< last entry of the list
90 numlist weekdays
= { { 0, 1, 2, 3, 4, 5, 6 }, 7 };
91 numlist hours
= { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }, 24 };
93 extern char *userfile
;
94 extern FileListObject AccessLog
;
96 extern const struct ReadLogProcessStruct ReadSquidLog
;
97 extern const struct ReadLogProcessStruct ReadCommonLog
;
98 extern const struct ReadLogProcessStruct ReadSargLog
;
99 extern const struct ReadLogProcessStruct ReadExtLog
;
101 //! The list of the supported log formats.
102 static const struct ReadLogProcessStruct
const *LogFormats
[]=
110 //! The path to the sarg log file.
111 static char SargLogFile
[4096]="";
112 //! Handle to the sarg log file. NULL if not created.
113 static FILE *fp_log
=NULL
;
114 //! The number of records read from the input logs.
115 static long int totregsl
=0;
116 //! The number of records kept.
117 static long int totregsg
=0;
118 //! The number of records excluded.
119 static long int totregsx
=0;
120 //! The beginning of a linked list of user's file.
121 static struct userfilestruct
*first_user_file
=NULL
;
122 //! Count the number of occurence of each input log format.
123 static unsigned long int format_count
[sizeof(LogFormats
)/sizeof(*LogFormats
)];
124 //! The minimum date found in the input logs.
125 static int mindate
=0;
126 static int maxdate
=0;
127 //! Count the number of excluded records.
128 static unsigned long int excluded_count
[ER_Last
];
131 Read a single log file.
133 \param arq The log file name to read.
135 static void ReadOneLogFile(struct ReadLogDataStruct
*Filter
,const char *arq
)
143 char tmp3
[MAXLEN
]="";
144 char download_url
[MAXLEN
];
145 char smartfilter
[MAXLEN
];
147 int current_format_idx
;
148 int OutputNonZero
= REPORT_EVERY_X_LINES
;
153 int maxopenfiles
=MAX_OPEN_USER_FILES
;
154 int successive_errors
=0;
156 unsigned long int recs1
=0UL;
157 unsigned long int recs2
=0UL;
161 bool download_flag
=false;
163 enum ReadLogReturnCodeEnum log_entry_status
;
165 struct getwordstruct gwarea
;
166 struct userfilestruct
*prev_ufile
;
167 struct userinfostruct
*uinfo
;
168 struct userfilestruct
*ufile
;
169 struct userfilestruct
*ufile1
;
170 struct ReadLogStruct log_entry
;
171 const struct ReadLogProcessStruct
*current_format
=NULL
;
174 current_format_idx
=-1;
175 for (x
=0 ; x
<sizeof(LogFormats
)/sizeof(*LogFormats
) ; x
++)
176 if (LogFormats
[x
]->NewFile
)
177 LogFormats
[x
]->NewFile(arq
);
179 if (arq
[0]=='-' && arq
[1]=='\0') {
181 debuga(_("Reading access log file: from stdin\n"));
185 if (Filter
->DateRange
[0]!='\0') {
186 if (stat(arq
,&logstat
)!=0) {
187 debuga(_("Cannot get the modification time of input log file %s (%s). Processing it anyway\n"),arq
,strerror(errno
));
189 struct tm
*logtime
=localtime(&logstat
.st_mtime
);
190 if ((logtime
->tm_year
+1900)*10000+(logtime
->tm_mon
+1)*100+logtime
->tm_mday
<dfrom
) {
191 debuga(_("Ignoring old log file %s\n"),arq
);
196 fp_in
=decomp(arq
,&from_pipe
);
198 debuga(_("Cannot open input log file \"%s\": %s\n"),arq
,strerror(errno
));
201 if(debug
) debuga(_("Reading access log file: %s\n"),arq
);
210 // pre-read the file only if we have to show stats
211 if (ShowReadStatistics
&& ShowReadPercent
&& !from_stdin
&& !from_pipe
) {
216 while ((nread
=fread(tmp4
,1,sizeof(tmp4
),fp_in
))>0) {
217 for (i
=0 ; i
<nread
; i
++)
219 if (tmp4
[i
]!='\n' && tmp4
[i
]!='\r') {
223 if (tmp4
[i
]=='\n' || tmp4
[i
]=='\r') {
230 printf(_("SARG: Records in file: %lu, reading: %3.2f%%"),recs1
,(float) 0);
235 if ((line
=longline_create())==NULL
) {
236 debuga(_("Not enough memory to read log file %s\n"),arq
);
240 while ((linebuf
=longline_read(fp_in
,line
))!=NULL
) {
244 if (ShowReadStatistics
&& --OutputNonZero
<=0) {
246 double perc
= recs2
* 100. / recs1
;
247 printf(_("SARG: Records in file: %lu, reading: %3.2lf%%"),recs2
,perc
);
249 printf(_("SARG: Records in file: %lu"),recs2
);
253 OutputNonZero
= REPORT_EVERY_X_LINES
;
257 The following checks are retained here as I don't know to
258 what format they apply. They date back to pre 2.4 versions.
260 //if(blen < 58) continue; //this test conflict with the reading of the sarg log header line
261 if(strstr(linebuf
,"HTTP/0.0") != 0) {//recorded by squid when encountering an incomplete query
262 excluded_count
[ER_IncompleteQuery
]++;
265 if(strstr(linebuf
,"logfile turned over") != 0) {//reported by newsyslog
266 excluded_count
[ER_LogfileTurnedOver
]++;
271 if(ExcludeString
[0] != '\0') {
273 getword_start(&gwarea
,ExcludeString
);
274 while(strchr(gwarea
.current
,':') != 0) {
275 if (getword_multisep(val1
,sizeof(val1
),&gwarea
,':')<0) {
276 debuga(_("Maybe you have a broken record or garbage in your exclusion string\n"));
279 if((str
=(char *) strstr(linebuf
,val1
)) != (char *) NULL
) {
284 if(!exstring
&& (str
=(char *) strstr(linebuf
,gwarea
.current
)) != (char *) NULL
)
287 excluded_count
[ER_ExcludeString
]++;
294 printf("BUF=%s\n",linebuf
);
297 log_entry_status
=RLRC_Unknown
;
298 memset(&log_entry
,0,sizeof(log_entry
));
299 if (current_format
) {
300 log_entry_status
=current_format
->ReadEntry(linebuf
,&log_entry
);
303 // find out what line format to use
304 if (log_entry_status
==RLRC_Unknown
) {
305 for (x
=0 ; x
<(int)(sizeof(LogFormats
)/sizeof(*LogFormats
)) ; x
++) {
306 if (LogFormats
[x
]==current_format
) continue;
307 memset(&log_entry
,0,sizeof(log_entry
));
308 log_entry_status
=LogFormats
[x
]->ReadEntry(linebuf
,&log_entry
);
309 if (log_entry_status
!=RLRC_Unknown
) break;
311 if (x
>=(int)(sizeof(LogFormats
)/sizeof(*LogFormats
))) {
312 if (++successive_errors
>NumLogSuccessiveErrors
) {
313 debuga(ngettext("%d consecutive error found in the input log file %s\n",
314 "%d consecutive errors found in the input log file %s\n",successive_errors
),successive_errors
,arq
);
317 if (NumLogTotalErrors
>=0 && ++total_errors
>NumLogTotalErrors
) {
318 debuga(ngettext("%d error found in the input log file (last in %s)\n",
319 "%d errors found in the input log file (last in %s)\n",total_errors
),total_errors
,arq
);
322 debuga(_("The following line read from %s could not be parsed and is ignored\n%s\n"),arq
,linebuf
);
323 excluded_count
[ER_UnknownFormat
]++;
326 current_format
=LogFormats
[x
];
327 current_format_idx
=x
;
329 /* TRANSLATORS: The argument is the log format name as translated by you. */
330 debuga(_("Log format identified as \"%s\" for %s\n"),_(current_format
->Name
),arq
);
334 if (log_entry_status
==RLRC_Ignore
) {
335 excluded_count
[ER_FormatData
]++;
338 if (current_format_idx
<0 || current_format
==NULL
) {
339 debuga(_("Sarg failed to determine the format of the input log file %s\n"),arq
);
342 if (log_entry_status
==RLRC_InternalError
) {
343 debuga(_("Internal error encountered while processing %s\nSee previous message to know the reason for that error.\n"),arq
);
346 format_count
[current_format_idx
]++;
348 if (!fp_log
&& ParsedOutputLog
[0] && current_format
!=&ReadSargLog
) {
349 if(access(ParsedOutputLog
,R_OK
) != 0) {
350 my_mkdir(ParsedOutputLog
);
352 if (snprintf(SargLogFile
,sizeof(SargLogFile
),"%s/sarg_temp.log",ParsedOutputLog
)>=sizeof(SargLogFile
)) {
353 debuga(_("File name too long: %s/sarg_temp.log\n"),ParsedOutputLog
);
356 if((fp_log
=MY_FOPEN(SargLogFile
,"w"))==NULL
) {
357 debuga(_("(log) Cannot open log file %s: %s\n"),SargLogFile
,strerror(errno
));
360 fputs("*** SARG Log ***\n",fp_log
);
363 if (log_entry
.Ip
==NULL
) {
364 debuga(_("Unknown input log file format: no IP addresses\n"));
367 if (log_entry
.User
==NULL
) {
368 debuga(_("Unknown input log file format: no user\n"));
371 if (log_entry
.Url
==NULL
) {
372 debuga(_("Unknown input log file format: no URL\n"));
376 idata
=builddia(log_entry
.EntryTime
.tm_mday
,log_entry
.EntryTime
.tm_mon
+1,log_entry
.EntryTime
.tm_year
+1900);
378 printf("DATE=%s IDATA=%d DFROM=%d DUNTIL=%d\n",Filter
->DateRange
,idata
,dfrom
,duntil
);
380 if(Filter
->DateRange
[0] != '\0'){
381 if(idata
< dfrom
|| idata
> duntil
) {
382 excluded_count
[ER_OutOfDateRange
]++;
387 // Record only hours usage which is required
388 if( bsearch( &( log_entry
.EntryTime
.tm_wday
), weekdays
.list
, weekdays
.len
, sizeof( int ), compar
) == NULL
) {
389 excluded_count
[ER_OutOfWDayRange
]++;
393 if( bsearch( &( log_entry
.EntryTime
.tm_hour
), hours
.list
, hours
.len
, sizeof( int ), compar
) == NULL
) {
394 excluded_count
[ER_OutOfHourRange
]++;
399 if(strlen(log_entry
.User
) > MAX_USER_LEN
) {
400 if (debugm
) printf(_("User ID too long: %s\n"),log_entry
.User
);
401 excluded_count
[ER_UserNameTooLong
]++;
407 if(IncludeUsers
[0] != '\0') {
408 snprintf(val1
,sizeof(val1
),":%s:",log_entry
.User
);
409 if((str
=(char *) strstr(IncludeUsers
,val1
)) == (char *) NULL
) {
410 excluded_count
[ER_User
]++;
415 if(vercode(log_entry
.HttpCode
)) {
416 if (debugm
) printf(_("Excluded code: %s\n"),log_entry
.HttpCode
);
417 excluded_count
[ER_HttpCode
]++;
422 if(testvaliduserchar(log_entry
.User
)) {
423 excluded_count
[ER_InvalidUserChar
]++;
427 // replace any tab by a single space
428 for (str
=log_entry
.Url
; *str
; str
++)
429 if (*str
=='\t') *str
=' ';
430 for (str
=log_entry
.HttpCode
; *str
; str
++)
431 if (*str
=='\t') *str
=' ';
433 if (current_format
!=&ReadSargLog
) {
435 The full URL is not saved in sarg log. There is no point in testing the URL to detect
438 download_flag
=is_download_suffix(log_entry
.Url
);
440 safe_strcpy(download_url
,log_entry
.Url
,sizeof(download_url
));
445 url
=process_url(log_entry
.Url
,LongUrl
);
446 if (!url
|| url
[0] == '\0') {
447 excluded_count
[ER_NoUrl
]++;
452 if(strcmp(addr
,log_entry
.Ip
)!=0) {
453 excluded_count
[ER_UntrackedIpAddr
]++;
457 if(Filter
->HostFilter
) {
458 if(!vhexclude(url
)) {
459 if (debugm
) printf(_("Excluded site: %s\n"),url
);
460 excluded_count
[ER_Url
]++;
466 if(Filter
->StartTime
>= 0 && Filter
->EndTime
>= 0) {
467 hmr
=log_entry
.EntryTime
.tm_hour
*100+log_entry
.EntryTime
.tm_min
;
468 if(hmr
< Filter
->StartTime
|| hmr
> Filter
->EndTime
) {
469 excluded_count
[ER_OutOfTimeRange
]++;
475 if(strstr(url
,site
)==0) {
476 excluded_count
[ER_UntrackedUrl
]++;
482 log_entry
.User
=log_entry
.Ip
;
486 if ((log_entry
.User
[0]=='\0') || (log_entry
.User
[1]=='\0' && (log_entry
.User
[0]=='-' || log_entry
.User
[0]==' '))) {
487 if(RecordsWithoutUser
== RECORDWITHOUTUSER_IP
) {
488 log_entry
.User
=log_entry
.Ip
;
491 if(RecordsWithoutUser
== RECORDWITHOUTUSER_IGNORE
) {
492 excluded_count
[ER_NoUser
]++;
495 if(RecordsWithoutUser
== RECORDWITHOUTUSER_EVERYBODY
)
496 log_entry
.User
="everybody";
498 if(NtlmUserFormat
== NTLMUSERFORMAT_USER
) {
499 if ((str
=strchr(log_entry
.User
,'+'))!=NULL
|| (str
=strchr(log_entry
.User
,'\\'))!=NULL
|| (str
=strchr(log_entry
.User
,'_'))!=NULL
) {
500 log_entry
.User
=str
+1;
507 if(strcmp(log_entry
.User
,us
)!=0) {
508 excluded_count
[ER_UntrackedUser
]++;
513 if(Filter
->SysUsers
) {
514 snprintf(wuser
,sizeof(wuser
),":%s:",log_entry
.User
);
515 if(strstr(userfile
, wuser
) == 0) {
516 excluded_count
[ER_SysUser
]++;
521 if(Filter
->UserFilter
) {
522 if(!vuexclude(log_entry
.User
)) {
523 if (debugm
) printf(_("Excluded user: %s\n"),log_entry
.User
);
524 excluded_count
[ER_IgnoredUser
]++;
530 log_entry
.User
=process_user(log_entry
.User
);
531 if (log_entry
.User
[0]=='\0' || (log_entry
.User
[1]=='\0' && (log_entry
.User
[0]=='-' ||
532 log_entry
.User
[0]==' ' || log_entry
.User
[0]==':'))) {
533 excluded_count
[ER_NoUser
]++;
537 if (log_entry
.DataSize
<0) log_entry
.DataSize
=0;
539 if (log_entry
.ElapsedTime
<0) log_entry
.ElapsedTime
=0;
540 if (Filter
->max_elapsed
>0 && log_entry
.ElapsedTime
>Filter
->max_elapsed
) {
541 log_entry
.ElapsedTime
=0;
544 if((str
=(char *) strstr(linebuf
, "[SmartFilter:")) != (char *) NULL
) {
546 snprintf(smartfilter
,sizeof(smartfilter
),"\"%s\"",str
+1);
547 } else strcpy(smartfilter
,"\"\"");
551 for (ufile
=first_user_file
; ufile
&& strcmp(log_entry
.User
,ufile
->user
->id
)!=0 ; ufile
=ufile
->next
) {
553 if (ufile
->file
) nopen
++;
556 ufile
=malloc(sizeof(*ufile
));
558 debuga(_("Not enough memory to store the user %s\n"),log_entry
.User
);
561 memset(ufile
,0,sizeof(*ufile
));
562 ufile
->next
=first_user_file
;
563 first_user_file
=ufile
;
564 uinfo
=userinfo_create(log_entry
.User
);
566 uinfo
->id_is_ip
=id_is_ip
;
570 prev_ufile
->next
=ufile
->next
;
571 ufile
->next
=first_user_file
;
572 first_user_file
=ufile
;
575 #ifdef ENABLE_DOUBLE_CHECK_DATA
576 ufile
->user
->nbytes
+=log_entry
.DataSize
;
577 ufile
->user
->elap
+=log_entry
.ElapsedTime
;
580 if (ufile
->file
==NULL
) {
581 if (nopen
>=maxopenfiles
) {
583 for (ufile1
=first_user_file
; ufile1
; ufile1
=ufile1
->next
) {
584 if (ufile1
->file
!=NULL
) {
585 if (x
>=maxopenfiles
) {
586 if (fclose(ufile1
->file
)==EOF
) {
587 debuga(_("Write error in the log file of user %s: %s\n"),ufile1
->user
->id
,strerror(errno
));
596 if (snprintf (tmp3
, sizeof(tmp3
), "%s/%s.user_unsort", tmp
, ufile
->user
->filename
)>=sizeof(tmp3
)) {
597 debuga(_("Temporary user file name too long: %s/%s.user_unsort\n"), tmp
, ufile
->user
->filename
);
600 if ((ufile
->file
= MY_FOPEN (tmp3
, "a")) == NULL
) {
601 debuga(_("(log) Cannot open temporary file %s: %s\n"), tmp3
, strerror(errno
));
606 strftime(dia
, sizeof(dia
), "%d/%m/%Y",&log_entry
.EntryTime
);
607 strftime(hora
,sizeof(hora
),"%H:%M:%S",&log_entry
.EntryTime
);
609 if (fprintf(ufile
->file
, "%s\t%s\t%s\t%s\t%"PRIu64
"\t%s\t%ld\t%s\n",dia
,hora
,
610 log_entry
.Ip
,url
,(uint64_t)log_entry
.DataSize
,
611 log_entry
.HttpCode
,log_entry
.ElapsedTime
,smartfilter
)<=0) {
612 debuga(_("Write error in the log file of user %s\n"),log_entry
.User
);
617 if (fp_log
&& current_format
!=&ReadSargLog
) {
618 fprintf(fp_log
, "%s\t%s\t%s\t%s\t%s\t%"PRIu64
"\t%s\t%ld\t%s\n",dia
,hora
,
619 log_entry
.User
,log_entry
.Ip
,url
,(uint64_t)log_entry
.DataSize
,
620 log_entry
.HttpCode
,log_entry
.ElapsedTime
,smartfilter
);
625 denied_write(&log_entry
);
626 authfail_write(&log_entry
);
627 download_write(&log_entry
,download_url
);
629 if (current_format
!=&ReadSargLog
) {
630 if (period
.start
.tm_year
==0 || idata
<mindate
|| compare_date(&period
.start
,&log_entry
.EntryTime
)>0){
632 memcpy(&period
.start
,&log_entry
.EntryTime
,sizeof(log_entry
.EntryTime
));
634 if (period
.end
.tm_year
==0 || idata
>maxdate
|| compare_date(&period
.end
,&log_entry
.EntryTime
)<0) {
636 memcpy(&period
.end
,&log_entry
.EntryTime
,sizeof(log_entry
.EntryTime
));
641 printf("IP=\t%s\n",log_entry
.Ip
);
642 printf("USER=\t%s\n",log_entry
.User
);
643 printf("ELAP=\t%ld\n",log_entry
.ElapsedTime
);
644 printf("DATE=\t%s\n",dia
);
645 printf("TIME=\t%s\n",hora
);
646 //printf("FUNC=\t%s\n",fun);
647 printf("URL=\t%s\n",url
);
648 printf("CODE=\t%s\n",log_entry
.HttpCode
);
649 printf("LEN=\t%"PRIu64
"\n",(uint64_t)log_entry
.DataSize
);
652 longline_destroy(&line
);
659 if (ShowReadStatistics
) {
661 printf(_("SARG: Records in file: %lu, reading: %3.2f%%\n"),recs2
, (float) 100 );
663 printf(_("SARG: Records in file: %lu\n"),recs2
);
670 * Display a line with the excluded entries count.
672 * \param Explain A translated string explaining the exluded count.
673 * \param Reason The reason number.
675 static void DisplayExcludeCount(const char *Explain
,enum ExcludeReasonEnum Reason
)
677 if (excluded_count
[Reason
]>0) {
678 debuga(" %s: %lu\n",Explain
,excluded_count
[Reason
]);
685 \param Filter The filtering parameters for the file to load.
687 \retval 1 Records found.
688 \retval 0 No record found.
690 int ReadLogFile(struct ReadLogDataStruct
*Filter
)
694 struct userfilestruct
*ufile
;
695 struct userfilestruct
*ufile1
;
696 FileListIterator FIter
;
699 for (x
=0 ; x
<sizeof(format_count
)/sizeof(*format_count
) ; x
++) format_count
[x
]=0;
700 for (x
=0 ; x
<sizeof(excluded_count
)/sizeof(*excluded_count
) ; x
++) excluded_count
[x
]=0;
701 first_user_file
=NULL
;
709 FIter
=FileListIter_Open(AccessLog
);
710 while ((file
=FileListIter_Next(FIter
))!=NULL
)
711 ReadOneLogFile(Filter
,file
);
712 FileListIter_Close(FIter
);
716 char val4
[4096];//val4 must not be bigger than SargLogFile without fixing the strcpy below
718 if (fclose(fp_log
)==EOF
) {
719 debuga(_("Write error in %s: %s\n"),SargLogFile
,strerror(errno
));
722 strftime(val2
,sizeof(val2
),"%d%m%Y_%H%M",&period
.start
);
723 strftime(val1
,sizeof(val1
),"%d%m%Y_%H%M",&period
.end
);
724 if (snprintf(val4
,sizeof(val4
),"%s/sarg-%s-%s.log",ParsedOutputLog
,val2
,val1
)>=sizeof(val4
)) {
725 debuga(_("File name too long: %s/sarg-%s-%s.log\n"),ParsedOutputLog
,val2
,val1
);
728 if (rename(SargLogFile
,val4
)) {
729 debuga(_("failed to rename %s to %s - %s\n"),SargLogFile
,val4
,strerror(errno
));
731 strcpy(SargLogFile
,val4
);
733 if(strcmp(ParsedOutputLogCompress
,"nocompress") != 0 && ParsedOutputLogCompress
[0] != '\0') {
735 No double quotes around ParsedOutputLogCompress because it may contain command line options. If double quotes are
736 necessary around the command name, put them in the configuration file.
738 if (snprintf(val1
,sizeof(val1
),"%s \"%s\"",ParsedOutputLogCompress
,SargLogFile
)>=sizeof(val1
)) {
739 debuga(_("Command too long: %s \"%s\"\n"),ParsedOutputLogCompress
,SargLogFile
);
742 cstatus
=system(val1
);
743 if (!WIFEXITED(cstatus
) || WEXITSTATUS(cstatus
)) {
744 debuga(_("command return status %d\n"),WEXITSTATUS(cstatus
));
745 debuga(_("command: %s\n"),val1
);
751 debuga(_("Sarg parsed log saved as %s\n"),SargLogFile
);
758 for (ufile
=first_user_file
; ufile
; ufile
=ufile1
) {
760 if (ufile
->file
!=NULL
&& fclose(ufile
->file
)==EOF
) {
761 debuga(_("Write error in the log file of user %s: %s\n"),ufile
->user
->id
,strerror(errno
));
768 unsigned long int totalcount
=0;
770 debuga(_(" Records read: %ld, written: %ld, excluded: %ld\n"),totregsl
,totregsg
,totregsx
);
772 for (x
=sizeof(excluded_count
)/sizeof(*excluded_count
)-1 ; x
>=0 && excluded_count
[x
]>0 ; x
--);
774 debuga(_("Reasons for excluded entries:\n"));
775 DisplayExcludeCount(_("User name too long"),ER_UserNameTooLong
);
776 DisplayExcludeCount(_("Squid logged an incomplete query received from the client"),ER_IncompleteQuery
);
777 DisplayExcludeCount(_("Log file turned over"),ER_LogfileTurnedOver
);
778 DisplayExcludeCount(_("Excluded by \"exclude_string\" in sarg.conf"),ER_ExcludeString
);
779 DisplayExcludeCount(_("Unknown input log file format"),ER_UnknownFormat
);
780 DisplayExcludeCount(_("Line ignored by the input log format"),ER_FormatData
);
781 DisplayExcludeCount(_("Time outside the requested date range (-d)"),ER_OutOfDateRange
);
782 DisplayExcludeCount(_("Ignored week day (\"weekdays\" parameter in sarg.conf)"),ER_OutOfWDayRange
);
783 DisplayExcludeCount(_("Ignored hour (\"hours\" parameter in sarg.conf)"),ER_OutOfHourRange
);
784 DisplayExcludeCount(_("User is not in the \"include_users\" list"),ER_User
);
785 DisplayExcludeCount(_("HTTP code excluded by \"exclude_code\" file"),ER_HttpCode
);
786 DisplayExcludeCount(_("Invalid character found in user name"),ER_InvalidUserChar
);
787 DisplayExcludeCount(_("No URL in entry"),ER_NoUrl
);
788 DisplayExcludeCount(_("Not the IP address requested with -a"),ER_UntrackedIpAddr
);
789 DisplayExcludeCount(_("URL excluded by -c or \"exclude_hosts\""),ER_Url
);
790 DisplayExcludeCount(_("Entry time outside of requested hour range (-t)"),ER_OutOfTimeRange
);
791 DisplayExcludeCount(_("Not the URL requested by -s"),ER_UntrackedUrl
);
792 DisplayExcludeCount(_("No user in entry"),ER_NoUser
);
793 DisplayExcludeCount(_("Not the user requested by -u"),ER_UntrackedUser
);
794 DisplayExcludeCount(_("System user as defined by \"password\" in sarg.conf"),ER_SysUser
);
795 DisplayExcludeCount(_("User ignored by \"exclude_users\""),ER_IgnoredUser
);
798 for (x
=0 ; x
<sizeof(LogFormats
)/sizeof(*LogFormats
) ; x
++) {
799 if (format_count
[x
]>0) {
800 /* TRANSLATORS: It displays the number of lines found in the input log files
801 * for each supported log format. The log format name is the %s and is a string
802 * you translate somewhere else. */
803 debuga(_("%s: %lu entries\n"),_(LogFormats
[x
]->Name
),format_count
[x
]);
804 totalcount
+=format_count
[x
];
808 if (totalcount
==0 && totregsg
)
809 debuga(_("Log with invalid format\n"));
813 debugaz(_("period=%s\n"),period
.text
);
815 return((totregsg
!=0) ? 1 : 0);