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
];
129 //! Earliest date found in the log.
130 static int EarliestDate
=-1;
131 //! The earliest date in time format.
132 static struct tm EarliestDateTime
;
133 //! Latest date found in the log.
134 static int LatestDate
=-1;
135 //! The latest date in time format.
136 static struct tm LatestDateTime
;
139 Read a single log file.
141 \param arq The log file name to read.
143 static void ReadOneLogFile(struct ReadLogDataStruct
*Filter
,const char *arq
)
151 char tmp3
[MAXLEN
]="";
152 char download_url
[MAXLEN
];
153 char smartfilter
[MAXLEN
];
156 int current_format_idx
;
157 int OutputNonZero
= REPORT_EVERY_X_LINES
;
162 int maxopenfiles
=MAX_OPEN_USER_FILES
;
163 int successive_errors
=0;
165 unsigned long int recs1
=0UL;
166 unsigned long int recs2
=0UL;
170 bool download_flag
=false;
172 enum ReadLogReturnCodeEnum log_entry_status
;
174 struct getwordstruct gwarea
;
175 struct userfilestruct
*prev_ufile
;
176 struct userinfostruct
*uinfo
;
177 struct userfilestruct
*ufile
;
178 struct userfilestruct
*ufile1
;
179 struct ReadLogStruct log_entry
;
180 const struct ReadLogProcessStruct
*current_format
=NULL
;
183 current_format_idx
=-1;
184 for (x
=0 ; x
<sizeof(LogFormats
)/sizeof(*LogFormats
) ; x
++)
185 if (LogFormats
[x
]->NewFile
)
186 LogFormats
[x
]->NewFile(arq
);
188 if (arq
[0]=='-' && arq
[1]=='\0') {
190 debuga(_("Reading access log file: from stdin\n"));
194 if (Filter
->DateRange
[0]!='\0') {
195 if (stat(arq
,&logstat
)!=0) {
196 debuga(_("Cannot get the modification time of input log file %s (%s). Processing it anyway\n"),arq
,strerror(errno
));
198 struct tm
*logtime
=localtime(&logstat
.st_mtime
);
199 if ((logtime
->tm_year
+1900)*10000+(logtime
->tm_mon
+1)*100+logtime
->tm_mday
<dfrom
) {
200 debuga(_("Ignoring old log file %s\n"),arq
);
205 fp_in
=decomp(arq
,&from_pipe
);
207 debuga(_("Cannot open input log file \"%s\": %s\n"),arq
,strerror(errno
));
210 if(debug
) debuga(_("Reading access log file: %s\n"),arq
);
219 // pre-read the file only if we have to show stats
220 if (ShowReadStatistics
&& ShowReadPercent
&& !from_stdin
&& !from_pipe
) {
225 while ((nread
=fread(tmp4
,1,sizeof(tmp4
),fp_in
))>0) {
226 for (i
=0 ; i
<nread
; i
++)
228 if (tmp4
[i
]!='\n' && tmp4
[i
]!='\r') {
232 if (tmp4
[i
]=='\n' || tmp4
[i
]=='\r') {
239 printf(_("SARG: Records in file: %lu, reading: %3.2f%%"),recs1
,(float) 0);
244 if ((line
=longline_create())==NULL
) {
245 debuga(_("Not enough memory to read log file %s\n"),arq
);
249 while ((linebuf
=longline_read(fp_in
,line
))!=NULL
) {
253 if (ShowReadStatistics
&& --OutputNonZero
<=0) {
255 double perc
= recs2
* 100. / recs1
;
256 printf(_("SARG: Records in file: %lu, reading: %3.2lf%%"),recs2
,perc
);
258 printf(_("SARG: Records in file: %lu"),recs2
);
262 OutputNonZero
= REPORT_EVERY_X_LINES
;
266 The following checks are retained here as I don't know to
267 what format they apply. They date back to pre 2.4 versions.
269 //if(blen < 58) continue; //this test conflict with the reading of the sarg log header line
270 if(strstr(linebuf
,"HTTP/0.0") != 0) {//recorded by squid when encountering an incomplete query
271 excluded_count
[ER_IncompleteQuery
]++;
274 if(strstr(linebuf
,"logfile turned over") != 0) {//reported by newsyslog
275 excluded_count
[ER_LogfileTurnedOver
]++;
280 if(ExcludeString
[0] != '\0') {
282 getword_start(&gwarea
,ExcludeString
);
283 while(strchr(gwarea
.current
,':') != 0) {
284 if (getword_multisep(val1
,sizeof(val1
),&gwarea
,':')<0) {
285 debuga(_("Maybe you have a broken record or garbage in your exclusion string\n"));
288 if((str
=(char *) strstr(linebuf
,val1
)) != (char *) NULL
) {
293 if(!exstring
&& (str
=(char *) strstr(linebuf
,gwarea
.current
)) != (char *) NULL
)
296 excluded_count
[ER_ExcludeString
]++;
303 printf("BUF=%s\n",linebuf
);
306 log_entry_status
=RLRC_Unknown
;
307 memset(&log_entry
,0,sizeof(log_entry
));
308 if (current_format
) {
309 log_entry_status
=current_format
->ReadEntry(linebuf
,&log_entry
);
312 // find out what line format to use
313 if (log_entry_status
==RLRC_Unknown
) {
314 for (x
=0 ; x
<(int)(sizeof(LogFormats
)/sizeof(*LogFormats
)) ; x
++) {
315 if (LogFormats
[x
]==current_format
) continue;
316 memset(&log_entry
,0,sizeof(log_entry
));
317 log_entry_status
=LogFormats
[x
]->ReadEntry(linebuf
,&log_entry
);
318 if (log_entry_status
!=RLRC_Unknown
) break;
320 if (x
>=(int)(sizeof(LogFormats
)/sizeof(*LogFormats
))) {
321 if (++successive_errors
>NumLogSuccessiveErrors
) {
322 debuga(ngettext("%d consecutive error found in the input log file %s\n",
323 "%d consecutive errors found in the input log file %s\n",successive_errors
),successive_errors
,arq
);
326 if (NumLogTotalErrors
>=0 && ++total_errors
>NumLogTotalErrors
) {
327 debuga(ngettext("%d error found in the input log file (last in %s)\n",
328 "%d errors found in the input log file (last in %s)\n",total_errors
),total_errors
,arq
);
331 debuga(_("The following line read from %s could not be parsed and is ignored\n%s\n"),arq
,linebuf
);
332 excluded_count
[ER_UnknownFormat
]++;
335 current_format
=LogFormats
[x
];
336 current_format_idx
=x
;
338 /* TRANSLATORS: The argument is the log format name as translated by you. */
339 debuga(_("Log format identified as \"%s\" for %s\n"),_(current_format
->Name
),arq
);
343 if (log_entry_status
==RLRC_Ignore
) {
344 excluded_count
[ER_FormatData
]++;
347 if (current_format_idx
<0 || current_format
==NULL
) {
348 debuga(_("Sarg failed to determine the format of the input log file %s\n"),arq
);
351 if (log_entry_status
==RLRC_InternalError
) {
352 debuga(_("Internal error encountered while processing %s\nSee previous message to know the reason for that error.\n"),arq
);
355 format_count
[current_format_idx
]++;
357 if (!fp_log
&& ParsedOutputLog
[0] && current_format
!=&ReadSargLog
) {
358 if(access(ParsedOutputLog
,R_OK
) != 0) {
359 my_mkdir(ParsedOutputLog
);
361 if (snprintf(SargLogFile
,sizeof(SargLogFile
),"%s/sarg_temp.log",ParsedOutputLog
)>=sizeof(SargLogFile
)) {
362 debuga(_("File name too long: %s/sarg_temp.log\n"),ParsedOutputLog
);
365 if((fp_log
=MY_FOPEN(SargLogFile
,"w"))==NULL
) {
366 debuga(_("(log) Cannot open log file %s: %s\n"),SargLogFile
,strerror(errno
));
369 fputs("*** SARG Log ***\n",fp_log
);
372 if (log_entry
.Ip
==NULL
) {
373 debuga(_("Unknown input log file format: no IP addresses\n"));
376 if (log_entry
.User
==NULL
) {
377 debuga(_("Unknown input log file format: no user\n"));
380 if (log_entry
.Url
==NULL
) {
381 debuga(_("Unknown input log file format: no URL\n"));
385 idata
=builddia(log_entry
.EntryTime
.tm_mday
,log_entry
.EntryTime
.tm_mon
+1,log_entry
.EntryTime
.tm_year
+1900);
387 printf("DATE=%s IDATA=%d DFROM=%d DUNTIL=%d\n",Filter
->DateRange
,idata
,dfrom
,duntil
);
389 if (EarliestDate
<0 || idata
<EarliestDate
) {
391 memcpy(&EarliestDateTime
,&log_entry
.EntryTime
,sizeof(struct tm
));
393 if (LatestDate
<0 || idata
>LatestDate
) {
395 memcpy(&LatestDateTime
,&log_entry
.EntryTime
,sizeof(struct tm
));
397 if(Filter
->DateRange
[0] != '\0'){
398 if(idata
< dfrom
|| idata
> duntil
) {
399 excluded_count
[ER_OutOfDateRange
]++;
404 // Record only hours usage which is required
405 if( bsearch( &( log_entry
.EntryTime
.tm_wday
), weekdays
.list
, weekdays
.len
, sizeof( int ), compar
) == NULL
) {
406 excluded_count
[ER_OutOfWDayRange
]++;
410 if( bsearch( &( log_entry
.EntryTime
.tm_hour
), hours
.list
, hours
.len
, sizeof( int ), compar
) == NULL
) {
411 excluded_count
[ER_OutOfHourRange
]++;
416 if(strlen(log_entry
.User
) > MAX_USER_LEN
) {
417 if (debugm
) printf(_("User ID too long: %s\n"),log_entry
.User
);
418 excluded_count
[ER_UserNameTooLong
]++;
424 if(IncludeUsers
[0] != '\0') {
425 snprintf(val1
,sizeof(val1
),":%s:",log_entry
.User
);
426 if((str
=(char *) strstr(IncludeUsers
,val1
)) == (char *) NULL
) {
427 excluded_count
[ER_User
]++;
432 if(vercode(log_entry
.HttpCode
)) {
433 if (debugm
) printf(_("Excluded code: %s\n"),log_entry
.HttpCode
);
434 excluded_count
[ER_HttpCode
]++;
439 if(testvaliduserchar(log_entry
.User
)) {
440 excluded_count
[ER_InvalidUserChar
]++;
444 // replace any tab by a single space
445 for (str
=log_entry
.Url
; *str
; str
++)
446 if (*str
=='\t') *str
=' ';
447 for (str
=log_entry
.HttpCode
; *str
; str
++)
448 if (*str
=='\t') *str
=' ';
450 if (current_format
!=&ReadSargLog
) {
452 The full URL is not saved in sarg log. There is no point in testing the URL to detect
455 download_flag
=is_download_suffix(log_entry
.Url
);
457 safe_strcpy(download_url
,log_entry
.Url
,sizeof(download_url
));
462 url
=process_url(log_entry
.Url
,LongUrl
);
463 if (!url
|| url
[0] == '\0') {
464 excluded_count
[ER_NoUrl
]++;
469 if(strcmp(addr
,log_entry
.Ip
)!=0) {
470 excluded_count
[ER_UntrackedIpAddr
]++;
474 if(Filter
->HostFilter
) {
475 if(!vhexclude(url
)) {
476 if (debugm
) printf(_("Excluded site: %s\n"),url
);
477 excluded_count
[ER_Url
]++;
483 if(Filter
->StartTime
>= 0 && Filter
->EndTime
>= 0) {
484 hmr
=log_entry
.EntryTime
.tm_hour
*100+log_entry
.EntryTime
.tm_min
;
485 if(hmr
< Filter
->StartTime
|| hmr
> Filter
->EndTime
) {
486 excluded_count
[ER_OutOfTimeRange
]++;
492 if(strstr(url
,site
)==0) {
493 excluded_count
[ER_UntrackedUrl
]++;
499 log_entry
.User
=log_entry
.Ip
;
503 if ((log_entry
.User
[0]=='\0') || (log_entry
.User
[1]=='\0' && (log_entry
.User
[0]=='-' || log_entry
.User
[0]==' '))) {
504 if(RecordsWithoutUser
== RECORDWITHOUTUSER_IP
) {
505 log_entry
.User
=log_entry
.Ip
;
508 if(RecordsWithoutUser
== RECORDWITHOUTUSER_IGNORE
) {
509 excluded_count
[ER_NoUser
]++;
512 if(RecordsWithoutUser
== RECORDWITHOUTUSER_EVERYBODY
)
513 log_entry
.User
="everybody";
515 if(NtlmUserFormat
== NTLMUSERFORMAT_USER
) {
516 if ((str
=strchr(log_entry
.User
,'+'))!=NULL
|| (str
=strchr(log_entry
.User
,'\\'))!=NULL
|| (str
=strchr(log_entry
.User
,'_'))!=NULL
) {
517 log_entry
.User
=str
+1;
524 if(strcmp(log_entry
.User
,us
)!=0) {
525 excluded_count
[ER_UntrackedUser
]++;
530 if(Filter
->SysUsers
) {
531 snprintf(wuser
,sizeof(wuser
),":%s:",log_entry
.User
);
532 if(strstr(userfile
, wuser
) == 0) {
533 excluded_count
[ER_SysUser
]++;
538 if(Filter
->UserFilter
) {
539 if(!vuexclude(log_entry
.User
)) {
540 if (debugm
) printf(_("Excluded user: %s\n"),log_entry
.User
);
541 excluded_count
[ER_IgnoredUser
]++;
547 user
=process_user(log_entry
.User
);
548 if (log_entry
.User
!=user
) {
552 if (log_entry
.User
[0]=='\0' || (log_entry
.User
[1]=='\0' && (log_entry
.User
[0]=='-' ||
553 log_entry
.User
[0]==' ' || log_entry
.User
[0]==':'))) {
554 excluded_count
[ER_NoUser
]++;
558 if (log_entry
.DataSize
<0) log_entry
.DataSize
=0;
560 if (log_entry
.ElapsedTime
<0) log_entry
.ElapsedTime
=0;
561 if (Filter
->max_elapsed
>0 && log_entry
.ElapsedTime
>Filter
->max_elapsed
) {
562 log_entry
.ElapsedTime
=0;
565 if((str
=(char *) strstr(linebuf
, "[SmartFilter:")) != (char *) NULL
) {
567 snprintf(smartfilter
,sizeof(smartfilter
),"\"%s\"",str
+1);
568 } else strcpy(smartfilter
,"\"\"");
572 for (ufile
=first_user_file
; ufile
&& strcmp(log_entry
.User
,ufile
->user
->id
)!=0 ; ufile
=ufile
->next
) {
574 if (ufile
->file
) nopen
++;
577 ufile
=malloc(sizeof(*ufile
));
579 debuga(_("Not enough memory to store the user %s\n"),log_entry
.User
);
582 memset(ufile
,0,sizeof(*ufile
));
583 ufile
->next
=first_user_file
;
584 first_user_file
=ufile
;
585 uinfo
=userinfo_create(log_entry
.User
,(id_is_ip
) ? NULL
: log_entry
.Ip
);
590 prev_ufile
->next
=ufile
->next
;
591 ufile
->next
=first_user_file
;
592 first_user_file
=ufile
;
595 #ifdef ENABLE_DOUBLE_CHECK_DATA
596 ufile
->user
->nbytes
+=log_entry
.DataSize
;
597 ufile
->user
->elap
+=log_entry
.ElapsedTime
;
600 if (ufile
->file
==NULL
) {
601 if (nopen
>=maxopenfiles
) {
603 for (ufile1
=first_user_file
; ufile1
; ufile1
=ufile1
->next
) {
604 if (ufile1
->file
!=NULL
) {
605 if (x
>=maxopenfiles
) {
606 if (fclose(ufile1
->file
)==EOF
) {
607 debuga(_("Write error in the log file of user %s: %s\n"),ufile1
->user
->id
,strerror(errno
));
616 if (snprintf (tmp3
, sizeof(tmp3
), "%s/%s.user_unsort", tmp
, ufile
->user
->filename
)>=sizeof(tmp3
)) {
617 debuga(_("Temporary user file name too long: %s/%s.user_unsort\n"), tmp
, ufile
->user
->filename
);
620 if ((ufile
->file
= MY_FOPEN (tmp3
, "a")) == NULL
) {
621 debuga(_("(log) Cannot open temporary file %s: %s\n"), tmp3
, strerror(errno
));
626 strftime(dia
, sizeof(dia
), "%d/%m/%Y",&log_entry
.EntryTime
);
627 strftime(hora
,sizeof(hora
),"%H:%M:%S",&log_entry
.EntryTime
);
629 if (fprintf(ufile
->file
, "%s\t%s\t%s\t%s\t%"PRIu64
"\t%s\t%ld\t%s\n",dia
,hora
,
630 log_entry
.Ip
,url
,(uint64_t)log_entry
.DataSize
,
631 log_entry
.HttpCode
,log_entry
.ElapsedTime
,smartfilter
)<=0) {
632 debuga(_("Write error in the log file of user %s\n"),log_entry
.User
);
637 if (fp_log
&& current_format
!=&ReadSargLog
) {
638 fprintf(fp_log
, "%s\t%s\t%s\t%s\t%s\t%"PRIu64
"\t%s\t%ld\t%s\n",dia
,hora
,
639 log_entry
.User
,log_entry
.Ip
,url
,(uint64_t)log_entry
.DataSize
,
640 log_entry
.HttpCode
,log_entry
.ElapsedTime
,smartfilter
);
645 denied_write(&log_entry
);
646 authfail_write(&log_entry
);
647 if (download_flag
) download_write(&log_entry
,download_url
);
649 if (current_format
!=&ReadSargLog
) {
650 if (period
.start
.tm_year
==0 || idata
<mindate
|| compare_date(&period
.start
,&log_entry
.EntryTime
)>0){
652 memcpy(&period
.start
,&log_entry
.EntryTime
,sizeof(log_entry
.EntryTime
));
654 if (period
.end
.tm_year
==0 || idata
>maxdate
|| compare_date(&period
.end
,&log_entry
.EntryTime
)<0) {
656 memcpy(&period
.end
,&log_entry
.EntryTime
,sizeof(log_entry
.EntryTime
));
661 printf("IP=\t%s\n",log_entry
.Ip
);
662 printf("USER=\t%s\n",log_entry
.User
);
663 printf("ELAP=\t%ld\n",log_entry
.ElapsedTime
);
664 printf("DATE=\t%s\n",dia
);
665 printf("TIME=\t%s\n",hora
);
666 //printf("FUNC=\t%s\n",fun);
667 printf("URL=\t%s\n",url
);
668 printf("CODE=\t%s\n",log_entry
.HttpCode
);
669 printf("LEN=\t%"PRIu64
"\n",(uint64_t)log_entry
.DataSize
);
672 longline_destroy(&line
);
679 if (ShowReadStatistics
) {
681 printf(_("SARG: Records in file: %lu, reading: %3.2f%%\n"),recs2
, (float) 100 );
683 printf(_("SARG: Records in file: %lu\n"),recs2
);
690 * Display a line with the excluded entries count.
692 * \param Explain A translated string explaining the exluded count.
693 * \param Reason The reason number.
695 static void DisplayExcludeCount(const char *Explain
,enum ExcludeReasonEnum Reason
)
697 if (excluded_count
[Reason
]>0) {
698 debuga(" %s: %lu\n",Explain
,excluded_count
[Reason
]);
705 \param Filter The filtering parameters for the file to load.
707 \retval 1 Records found.
708 \retval 0 No record found.
710 int ReadLogFile(struct ReadLogDataStruct
*Filter
)
714 struct userfilestruct
*ufile
;
715 struct userfilestruct
*ufile1
;
716 FileListIterator FIter
;
719 for (x
=0 ; x
<sizeof(format_count
)/sizeof(*format_count
) ; x
++) format_count
[x
]=0;
720 for (x
=0 ; x
<sizeof(excluded_count
)/sizeof(*excluded_count
) ; x
++) excluded_count
[x
]=0;
721 first_user_file
=NULL
;
729 FIter
=FileListIter_Open(AccessLog
);
730 while ((file
=FileListIter_Next(FIter
))!=NULL
)
731 ReadOneLogFile(Filter
,file
);
732 FileListIter_Close(FIter
);
736 char val4
[4096];//val4 must not be bigger than SargLogFile without fixing the strcpy below
738 if (fclose(fp_log
)==EOF
) {
739 debuga(_("Write error in %s: %s\n"),SargLogFile
,strerror(errno
));
742 strftime(val2
,sizeof(val2
),"%d%m%Y_%H%M",&period
.start
);
743 strftime(val1
,sizeof(val1
),"%d%m%Y_%H%M",&period
.end
);
744 if (snprintf(val4
,sizeof(val4
),"%s/sarg-%s-%s.log",ParsedOutputLog
,val2
,val1
)>=sizeof(val4
)) {
745 debuga(_("File name too long: %s/sarg-%s-%s.log\n"),ParsedOutputLog
,val2
,val1
);
748 if (rename(SargLogFile
,val4
)) {
749 debuga(_("failed to rename %s to %s - %s\n"),SargLogFile
,val4
,strerror(errno
));
751 strcpy(SargLogFile
,val4
);
753 if(strcmp(ParsedOutputLogCompress
,"nocompress") != 0 && ParsedOutputLogCompress
[0] != '\0') {
755 No double quotes around ParsedOutputLogCompress because it may contain command line options. If double quotes are
756 necessary around the command name, put them in the configuration file.
758 if (snprintf(val1
,sizeof(val1
),"%s \"%s\"",ParsedOutputLogCompress
,SargLogFile
)>=sizeof(val1
)) {
759 debuga(_("Command too long: %s \"%s\"\n"),ParsedOutputLogCompress
,SargLogFile
);
762 cstatus
=system(val1
);
763 if (!WIFEXITED(cstatus
) || WEXITSTATUS(cstatus
)) {
764 debuga(_("command return status %d\n"),WEXITSTATUS(cstatus
));
765 debuga(_("command: %s\n"),val1
);
771 debuga(_("Sarg parsed log saved as %s\n"),SargLogFile
);
778 for (ufile
=first_user_file
; ufile
; ufile
=ufile1
) {
780 if (ufile
->file
!=NULL
&& fclose(ufile
->file
)==EOF
) {
781 debuga(_("Write error in the log file of user %s: %s\n"),ufile
->user
->id
,strerror(errno
));
788 unsigned long int totalcount
=0;
790 debuga(_(" Records read: %ld, written: %ld, excluded: %ld\n"),totregsl
,totregsg
,totregsx
);
792 for (x
=sizeof(excluded_count
)/sizeof(*excluded_count
)-1 ; x
>=0 && excluded_count
[x
]>0 ; x
--);
794 debuga(_("Reasons for excluded entries:\n"));
795 DisplayExcludeCount(_("User name too long"),ER_UserNameTooLong
);
796 DisplayExcludeCount(_("Squid logged an incomplete query received from the client"),ER_IncompleteQuery
);
797 DisplayExcludeCount(_("Log file turned over"),ER_LogfileTurnedOver
);
798 DisplayExcludeCount(_("Excluded by \"exclude_string\" in sarg.conf"),ER_ExcludeString
);
799 DisplayExcludeCount(_("Unknown input log file format"),ER_UnknownFormat
);
800 DisplayExcludeCount(_("Line ignored by the input log format"),ER_FormatData
);
801 DisplayExcludeCount(_("Time outside the requested date range (-d)"),ER_OutOfDateRange
);
802 DisplayExcludeCount(_("Ignored week day (\"weekdays\" parameter in sarg.conf)"),ER_OutOfWDayRange
);
803 DisplayExcludeCount(_("Ignored hour (\"hours\" parameter in sarg.conf)"),ER_OutOfHourRange
);
804 DisplayExcludeCount(_("User is not in the \"include_users\" list"),ER_User
);
805 DisplayExcludeCount(_("HTTP code excluded by \"exclude_code\" file"),ER_HttpCode
);
806 DisplayExcludeCount(_("Invalid character found in user name"),ER_InvalidUserChar
);
807 DisplayExcludeCount(_("No URL in entry"),ER_NoUrl
);
808 DisplayExcludeCount(_("Not the IP address requested with -a"),ER_UntrackedIpAddr
);
809 DisplayExcludeCount(_("URL excluded by -c or \"exclude_hosts\""),ER_Url
);
810 DisplayExcludeCount(_("Entry time outside of requested hour range (-t)"),ER_OutOfTimeRange
);
811 DisplayExcludeCount(_("Not the URL requested by -s"),ER_UntrackedUrl
);
812 DisplayExcludeCount(_("No user in entry"),ER_NoUser
);
813 DisplayExcludeCount(_("Not the user requested by -u"),ER_UntrackedUser
);
814 DisplayExcludeCount(_("System user as defined by \"password\" in sarg.conf"),ER_SysUser
);
815 DisplayExcludeCount(_("User ignored by \"exclude_users\""),ER_IgnoredUser
);
818 for (x
=0 ; x
<sizeof(LogFormats
)/sizeof(*LogFormats
) ; x
++) {
819 if (format_count
[x
]>0) {
820 /* TRANSLATORS: It displays the number of lines found in the input log files
821 * for each supported log format. The log format name is the %s and is a string
822 * you translate somewhere else. */
823 debuga(_("%s: %lu entries\n"),_(LogFormats
[x
]->Name
),format_count
[x
]);
824 totalcount
+=format_count
[x
];
828 if (totalcount
==0 && totregsg
)
829 debuga(_("Log with invalid format\n"));
832 return((totregsg
!=0) ? 1 : 0);
836 * Get the start and end date of the period covered by the log files.
838 void GetLogPeriod(struct tm
*Start
,struct tm
*End
)
840 if (EarliestDate
>=0) {
841 memcpy(Start
,&EarliestDateTime
,sizeof(struct tm
));
843 memset(Start
,0,sizeof(struct tm
));
846 memcpy(End
,&LatestDateTime
,sizeof(struct tm
));
848 memset(End
,0,sizeof(struct tm
));