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
;
586 * This id_is_ip stuff is just to store the string only once if the user is
587 * identified by its IP address instead of a distinct ID and IP address.
589 uinfo
=userinfo_create(log_entry
.User
,(id_is_ip
) ? NULL
: log_entry
.Ip
);
594 prev_ufile
->next
=ufile
->next
;
595 ufile
->next
=first_user_file
;
596 first_user_file
=ufile
;
599 #ifdef ENABLE_DOUBLE_CHECK_DATA
600 ufile
->user
->nbytes
+=log_entry
.DataSize
;
601 ufile
->user
->elap
+=log_entry
.ElapsedTime
;
604 if (ufile
->file
==NULL
) {
605 if (nopen
>=maxopenfiles
) {
607 for (ufile1
=first_user_file
; ufile1
; ufile1
=ufile1
->next
) {
608 if (ufile1
->file
!=NULL
) {
609 if (x
>=maxopenfiles
) {
610 if (fclose(ufile1
->file
)==EOF
) {
611 debuga(_("Write error in the log file of user %s: %s\n"),ufile1
->user
->id
,strerror(errno
));
620 if (snprintf (tmp3
, sizeof(tmp3
), "%s/%s.user_unsort", tmp
, ufile
->user
->filename
)>=sizeof(tmp3
)) {
621 debuga(_("Temporary user file name too long: %s/%s.user_unsort\n"), tmp
, ufile
->user
->filename
);
624 if ((ufile
->file
= MY_FOPEN (tmp3
, "a")) == NULL
) {
625 debuga(_("(log) Cannot open temporary file %s: %s\n"), tmp3
, strerror(errno
));
630 strftime(dia
, sizeof(dia
), "%d/%m/%Y",&log_entry
.EntryTime
);
631 strftime(hora
,sizeof(hora
),"%H:%M:%S",&log_entry
.EntryTime
);
633 if (fprintf(ufile
->file
, "%s\t%s\t%s\t%s\t%"PRIu64
"\t%s\t%ld\t%s\n",dia
,hora
,
634 log_entry
.Ip
,url
,(uint64_t)log_entry
.DataSize
,
635 log_entry
.HttpCode
,log_entry
.ElapsedTime
,smartfilter
)<=0) {
636 debuga(_("Write error in the log file of user %s\n"),log_entry
.User
);
641 if (fp_log
&& current_format
!=&ReadSargLog
) {
642 fprintf(fp_log
, "%s\t%s\t%s\t%s\t%s\t%"PRIu64
"\t%s\t%ld\t%s\n",dia
,hora
,
643 log_entry
.User
,log_entry
.Ip
,url
,(uint64_t)log_entry
.DataSize
,
644 log_entry
.HttpCode
,log_entry
.ElapsedTime
,smartfilter
);
649 denied_write(&log_entry
);
650 authfail_write(&log_entry
);
651 if (download_flag
) download_write(&log_entry
,download_url
);
653 if (current_format
!=&ReadSargLog
) {
654 if (period
.start
.tm_year
==0 || idata
<mindate
|| compare_date(&period
.start
,&log_entry
.EntryTime
)>0){
656 memcpy(&period
.start
,&log_entry
.EntryTime
,sizeof(log_entry
.EntryTime
));
658 if (period
.end
.tm_year
==0 || idata
>maxdate
|| compare_date(&period
.end
,&log_entry
.EntryTime
)<0) {
660 memcpy(&period
.end
,&log_entry
.EntryTime
,sizeof(log_entry
.EntryTime
));
665 printf("IP=\t%s\n",log_entry
.Ip
);
666 printf("USER=\t%s\n",log_entry
.User
);
667 printf("ELAP=\t%ld\n",log_entry
.ElapsedTime
);
668 printf("DATE=\t%s\n",dia
);
669 printf("TIME=\t%s\n",hora
);
670 //printf("FUNC=\t%s\n",fun);
671 printf("URL=\t%s\n",url
);
672 printf("CODE=\t%s\n",log_entry
.HttpCode
);
673 printf("LEN=\t%"PRIu64
"\n",(uint64_t)log_entry
.DataSize
);
676 longline_destroy(&line
);
683 if (ShowReadStatistics
) {
685 printf(_("SARG: Records in file: %lu, reading: %3.2f%%\n"),recs2
, (float) 100 );
687 printf(_("SARG: Records in file: %lu\n"),recs2
);
694 * Display a line with the excluded entries count.
696 * \param Explain A translated string explaining the exluded count.
697 * \param Reason The reason number.
699 static void DisplayExcludeCount(const char *Explain
,enum ExcludeReasonEnum Reason
)
701 if (excluded_count
[Reason
]>0) {
702 debuga(" %s: %lu\n",Explain
,excluded_count
[Reason
]);
709 \param Filter The filtering parameters for the file to load.
711 \retval 1 Records found.
712 \retval 0 No record found.
714 int ReadLogFile(struct ReadLogDataStruct
*Filter
)
718 struct userfilestruct
*ufile
;
719 struct userfilestruct
*ufile1
;
720 FileListIterator FIter
;
723 for (x
=0 ; x
<sizeof(format_count
)/sizeof(*format_count
) ; x
++) format_count
[x
]=0;
724 for (x
=0 ; x
<sizeof(excluded_count
)/sizeof(*excluded_count
) ; x
++) excluded_count
[x
]=0;
725 first_user_file
=NULL
;
733 FIter
=FileListIter_Open(AccessLog
);
734 while ((file
=FileListIter_Next(FIter
))!=NULL
)
735 ReadOneLogFile(Filter
,file
);
736 FileListIter_Close(FIter
);
740 char val4
[4096];//val4 must not be bigger than SargLogFile without fixing the strcpy below
742 if (fclose(fp_log
)==EOF
) {
743 debuga(_("Write error in %s: %s\n"),SargLogFile
,strerror(errno
));
746 strftime(val2
,sizeof(val2
),"%d%m%Y_%H%M",&period
.start
);
747 strftime(val1
,sizeof(val1
),"%d%m%Y_%H%M",&period
.end
);
748 if (snprintf(val4
,sizeof(val4
),"%s/sarg-%s-%s.log",ParsedOutputLog
,val2
,val1
)>=sizeof(val4
)) {
749 debuga(_("File name too long: %s/sarg-%s-%s.log\n"),ParsedOutputLog
,val2
,val1
);
752 if (rename(SargLogFile
,val4
)) {
753 debuga(_("failed to rename %s to %s - %s\n"),SargLogFile
,val4
,strerror(errno
));
755 strcpy(SargLogFile
,val4
);
757 if(strcmp(ParsedOutputLogCompress
,"nocompress") != 0 && ParsedOutputLogCompress
[0] != '\0') {
759 No double quotes around ParsedOutputLogCompress because it may contain command line options. If double quotes are
760 necessary around the command name, put them in the configuration file.
762 if (snprintf(val1
,sizeof(val1
),"%s \"%s\"",ParsedOutputLogCompress
,SargLogFile
)>=sizeof(val1
)) {
763 debuga(_("Command too long: %s \"%s\"\n"),ParsedOutputLogCompress
,SargLogFile
);
766 cstatus
=system(val1
);
767 if (!WIFEXITED(cstatus
) || WEXITSTATUS(cstatus
)) {
768 debuga(_("command return status %d\n"),WEXITSTATUS(cstatus
));
769 debuga(_("command: %s\n"),val1
);
775 debuga(_("Sarg parsed log saved as %s\n"),SargLogFile
);
782 for (ufile
=first_user_file
; ufile
; ufile
=ufile1
) {
784 if (ufile
->file
!=NULL
&& fclose(ufile
->file
)==EOF
) {
785 debuga(_("Write error in the log file of user %s: %s\n"),ufile
->user
->id
,strerror(errno
));
792 unsigned long int totalcount
=0;
794 debuga(_(" Records read: %ld, written: %ld, excluded: %ld\n"),totregsl
,totregsg
,totregsx
);
796 for (x
=sizeof(excluded_count
)/sizeof(*excluded_count
)-1 ; x
>=0 && excluded_count
[x
]>0 ; x
--);
798 debuga(_("Reasons for excluded entries:\n"));
799 DisplayExcludeCount(_("User name too long"),ER_UserNameTooLong
);
800 DisplayExcludeCount(_("Squid logged an incomplete query received from the client"),ER_IncompleteQuery
);
801 DisplayExcludeCount(_("Log file turned over"),ER_LogfileTurnedOver
);
802 DisplayExcludeCount(_("Excluded by \"exclude_string\" in sarg.conf"),ER_ExcludeString
);
803 DisplayExcludeCount(_("Unknown input log file format"),ER_UnknownFormat
);
804 DisplayExcludeCount(_("Line ignored by the input log format"),ER_FormatData
);
805 DisplayExcludeCount(_("Time outside the requested date range (-d)"),ER_OutOfDateRange
);
806 DisplayExcludeCount(_("Ignored week day (\"weekdays\" parameter in sarg.conf)"),ER_OutOfWDayRange
);
807 DisplayExcludeCount(_("Ignored hour (\"hours\" parameter in sarg.conf)"),ER_OutOfHourRange
);
808 DisplayExcludeCount(_("User is not in the \"include_users\" list"),ER_User
);
809 DisplayExcludeCount(_("HTTP code excluded by \"exclude_code\" file"),ER_HttpCode
);
810 DisplayExcludeCount(_("Invalid character found in user name"),ER_InvalidUserChar
);
811 DisplayExcludeCount(_("No URL in entry"),ER_NoUrl
);
812 DisplayExcludeCount(_("Not the IP address requested with -a"),ER_UntrackedIpAddr
);
813 DisplayExcludeCount(_("URL excluded by -c or \"exclude_hosts\""),ER_Url
);
814 DisplayExcludeCount(_("Entry time outside of requested hour range (-t)"),ER_OutOfTimeRange
);
815 DisplayExcludeCount(_("Not the URL requested by -s"),ER_UntrackedUrl
);
816 DisplayExcludeCount(_("No user in entry"),ER_NoUser
);
817 DisplayExcludeCount(_("Not the user requested by -u"),ER_UntrackedUser
);
818 DisplayExcludeCount(_("System user as defined by \"password\" in sarg.conf"),ER_SysUser
);
819 DisplayExcludeCount(_("User ignored by \"exclude_users\""),ER_IgnoredUser
);
822 for (x
=0 ; x
<sizeof(LogFormats
)/sizeof(*LogFormats
) ; x
++) {
823 if (format_count
[x
]>0) {
824 /* TRANSLATORS: It displays the number of lines found in the input log files
825 * for each supported log format. The log format name is the %s and is a string
826 * you translate somewhere else. */
827 debuga(_("%s: %lu entries\n"),_(LogFormats
[x
]->Name
),format_count
[x
]);
828 totalcount
+=format_count
[x
];
832 if (totalcount
==0 && totregsg
)
833 debuga(_("Log with invalid format\n"));
836 return((totregsg
!=0) ? 1 : 0);
840 * Get the start and end date of the period covered by the log files.
842 void GetLogPeriod(struct tm
*Start
,struct tm
*End
)
844 if (EarliestDate
>=0) {
845 memcpy(Start
,&EarliestDateTime
,sizeof(struct tm
));
847 memset(Start
,0,sizeof(struct tm
));
850 memcpy(End
,&LatestDateTime
,sizeof(struct tm
));
852 memset(End
,0,sizeof(struct tm
));