%! % POSTSCRIPT WEB HIT ANALYSIS ROUTINES % ==================================== % by Don Lancaster % Copyright c. 1996 by Don Lancaster and Synergetics, Box 809, % Thatcher AZ, 85552 (520) 428-4073. synergetics@tinaja.com % All commercial rights and all electronic media rights *fully* % reserved. Reposting is expressly forbidden. % Further support on www.tinaja.com % Consulting services available via don@tinaja.com % ==================================== % The PostScript general purpose computing language is ideal for % web hit analysis. Compared to certain commercial programs, the % routines are much faster and vastly gentler on disk drives. They % are also ridiculously easier to customize. Data is easily exported. % Here is a limited example that takes an ordinary PC resident net log % file in standard format and extracts useful info. % To use this routine, first read the *entire* file as a tutorial % textfile. Then MODIFY THE FILENAMES AND SUBDIRECTORY names to extract % useful log file information. Finally, route the program to the % Acrobat DISTILLER (!!!). % When Distiller is used as a general purpose host based PostScript % computer, it generates three outputs: An Acrobat .PDF file which % you throw away in this example. An on-screen report. And a little % noted .LOG file which holds your needed analyzed reports. % The .LOG file can be read in any editor or word processor. % Naturally, you can use the full graphic capabilities of PostScript % to create fancy charts and graphs of net log response as well. The % intent here is to show only the fundamentals, generating a text report. % One gotcha: In any PostScript file (string) where you need a "\", be % sure to use "\\" instead. % Here's an excerpt from a compantion utility file set. Have fun... %%%%%% (N) IMPROVED REPORT TOTAL SELECTED SUBDIRECTORY OR FILE HITS %%%%%%%% % Added features to (M) include sorting the reports, a total file report, % and a minimum hit clip. % This PostScript utility can be sent to Acrobat distiller 3.0 to % read a web log file, calculate hits and filtered hits by date % and report the results. % All processing is in RAM and only a single hard disk pass is required. % To use, change the log filename and your filter subdirectory name below. % Send to Acrobat DISTILLER. Read generated .LOG file. Throw away .PDF file. % An array of filenames and their totals are % created for the entire log file. The format is /totalstash [[(f1) f1count] % [(f2) f2count] ... [(fn) fncount] -null- -null- -null- ] def % /reporttotals reports the contents of the final file counts... /reporttotals { return flush % pretty print (Total filtered hits for entire log file:) print return return flush % header totalstash bubblesortx /stotstash exch store % sort highest first 0 1 usednames 1 sub {/posn exch store % for the list stotstash posn get 1 get minhits ge { % ignore dregs stotstash posn get dup 0 get print % get name ( had a total of ) print % and then 1 get 10 string cvs print % get count ( hits.) print return flush % and report } if % dregs } for % names } def % demo-- %% /totalstash [[(alpha)43][(bravo)27][(charlie)14][(delta)51]] def %% reporttotals % /addfhit adds one count to known stash or creates a new one /addfhit { /gotmatch false store % set match flag 127 string cvs /curfile exch store % grab filename 0 1 usednames 1 sub {/posn2 exch store % test for presence totalstash posn2 get 0 get curfile eq {totalstash posn2 get dup 1 get 1 add 1 exch % bump count if present put /gotmatch true store exit % and stop search } if } for gotmatch not % create new entry { totalstash usednames [curfile 1] put % two element array /usednames usednames 1 add store } if % bump name count } def % /inittotalaccum sets up a blank array for each new date... /inittotalaccum { /maxfiles 100 def % maximum anticipated filenames /totalstash [maxfiles {null} repeat] def % null array /usednames 0 def /hitsforall 0 def % global total hit counter /filteredhitsforall 0 def % global filtered hit counter } def % demo... %% inittotalaccum %% (aa) addfhit %% (aa) addfhit %% (aa) addfhit %% (bb) addfhit %% (aa) addfhit %% (aa) addfhit %% (aa) addfhit %% (cc) addfhit %% (bb) addfhit %% reporttotals %% % and the main code /chosensubdirectory (/glib) def % select your subdirectory or file /minhits 0 def /currentdate (X) def % running data stash /hitstoday 0 def % total hit accumulator /filteredhitstoday 0 def % subdirectory hit accumulator /inchits {/hitstoday hitstoday 1 add store} def /incfhits {/filteredhitstoday filteredhitstoday 1 add store} def % /bubblesortx accepts an array in /totalstash format and rearranges it so % the most used files go to the left... /bubblesortx { 0 usednames getinterval % strip the nulls /stotstash exch def stotstash mark % mark the stack exch aload pop counttomark /idx exch def % count the elements { 0 1 idx 1 sub {pop % don't need pointer 2 copy % check stack top pair 1 get exch 1 get exch % look at second array element lt {exch} if idx 1 roll} for idx 1 roll % blurp /idx idx 1 sub store % one less element idx 0 eq {exit} if} loop ] } def % /reportolddate reports the total and subdirectory hits for each day. % Usually just after the date changes. % The initial date is (X) and is unreported. /reportolddate { currentdate (X) ne {currentdate print ( had ) print hitstoday 20 string cvs print ( total hits and ) print filteredhitstoday 20 string cvs print ( ") print chosensubdirectory print (" filtered hits.) print return (This is a hit ratio of ) print filteredhitstoday hitstoday div 100 mul % optional find percentage 100 mul cvi 100 div % change to percent format 5 string cvs print (%.) print return % and report flush} if } def /reportalldates {return (The entire log file had ) print hitsforall 20 string cvs print ( total hits and ) print filteredhitsforall 20 string cvs print ( ") print chosensubdirectory print (" filtered hits.) print return (This is a hit ratio of ) print filteredhitsforall hitsforall div 100 mul % optional find percentage 100 mul cvi 100 div % change to percent format 5 string cvs print (%.) print return % and report flush} def % /procesfilename strips the filename out of the remainder of the log file % line by looking for the first trailing space. /processfilename { ( ) search {exch pop exch pop % filename ends with space chosensubdirectory search {pop pop % split out filename addfhit % add to list incfhits % bump hit count }{pop} ifelse} if % only if space present. } def % /isolategotfile pulls out log file lines that start with "GET... /isolategotfile { linebeyonddate ("GET ) search {pop pop 127 string cvs % DEREFERENCE string!! processfilename } {pop} ifelse % and process line } def % /grabdate&counthits isolates the day date and increments the hit counter % Note that PostScript strings are often defined by pointers to other strings % and can wildly change in any complex program. Dereferencing a string % with a ... 30 string cvs ... or whatever guarantees the new string % content is uniquely defined and will not unexpectedly change later. /grabdate&counthits { linehold ([) search { pop pop % get everything after brackets (:) search {exch pop exch % get everything before colon 200 string cvs % DEREFERNCE string!! /linebeyonddate exch store % save file info for further use inchits % add one to hit counter dup currentdate eq % is this same date as before { pop isolategotfile } % yes, get filename info only { 30 string cvs % DEREFERENCE string pointer!!! /newcurrentdate exch store % save new date reportolddate % report previous day hits /hitsforall hitsforall hitstoday add store % update totals /filteredhitsforall filteredhitsforall filteredhitstoday add store /hitstoday 0 store % reset hit counters /filteredhitstoday 0 store /currentdate newcurrentdate 30 string cvs store % DEREF again return (Processing ) print currentdate % print status message print (:) print return flush isolategotfile % get filename info } ifelse } {pop} ifelse } {pop} ifelse } def %%%%%%%%%%%%%%%%%%% USE EXAMPLE %%%%%%%%%%%%%%%%%%%% % IMPORTANT: Enter "\\" any time you mean "\" in the filename!!! /filename (c:\\Windows\\Desktop\\Zeketo~1\\webtrac.006) def % disk name of log file /chosensubdirectory (/glib) def % select subdirectory or file % must start with "/" /minhits 7 def % minimum reportable hits /crlf true def % ibm format? /strrx 256 string def % temp line stash /return {(\r) print crlf {(\n) print} if} def (starting processing of ) print filename print return return flush filename (r) file /myworkfile exch def % name of opened file inittotalaccum % clear counters {myworkfile strrx readline {/linehold % read log file a line at a time exch store % save log line grabdate&counthits} % check date and process further {myworkfile closefile exit} ifelse % exit on end of log file } loop reportolddate % for last date string completed reportalldates % global hit sums reporttotals % totals for file return return (rdone.) print flush % status % code resumes here % showpage or rest of program showpage % =================================== % Copyright c. 1996 by Don Lancaster and Synergetics, Box 809, % Thatcher AZ, 85552 (520) 428-4073. synergetics@tinaja.com % All commercial rights and all electronic media rights *fully* % reserved. Reposting is expressly forbidden. % Further support on www.tinaja.com % Consulting services available via don@tinaja.com % ====================================