REBOL [
    Title: "Report Cisco configuration changes"
    Purpose: {This is program to make a little report of data items
    from a log file that seems to be a standard output from various
    Cisco switches and routers and such.}                          
]

;; [---------------------------------------------------------------------------]
;; [ Files used in the program.                                                ]
;; [ We put these in one place so it is easy to change them as requirements    ]
;; [ evolve.                                                                   ]
;; [---------------------------------------------------------------------------]

CONFIG-LOG: %CiscoConfig.txt
OUTPUT-FILE: %CiscoConfig.htm

;; [---------------------------------------------------------------------------]
;; [ This script has been sanitized for giving away.  The code below can be    ]
;; [ used to make a test file to show the program's operation.                 ]
;; [---------------------------------------------------------------------------]

DEMO: true
DEMO-DATA:  
{6/22/2017 4:37 AM|111.222.333.161|111.222.333.161|SYS-5-CONFIG_I|69: 000068: *Jun 22 04:08:10: %SYS-5-CONFIG_I: Configured from console by console
6/22/2017 4:37 AM|111.222.333.161|111.222.333.161|SYS-5-CONFIG_I|70: 000069: *Jun 22 04:08:10: %SYS-5-CONFIG_I: Configured from console by console
6/22/2017 4:37 AM|111.222.333.161|111.222.333.161|SYS-5-CONFIG_I|72: 000071: *Jun 22 04:08:10: %SYS-5-CONFIG_I: Configured from console by console
6/22/2017 1:19 PM|111.222.333.141|111.222.333.141|SYS-5-CONFIG_I|26990: 026993: Jun 22 13:19:19: %SYS-5-CONFIG_I: Configured from console by jsmith on vty0 (10.1.250.78)
6/23/2017 8:42 AM|111.222.333.141|111.222.333.141|SYS-5-CONFIG_I|26998: 027001: Jun 23 08:42:24: %SYS-5-CONFIG_I: Configured from console by jsmith on vty0 (10.1.250.78)
6/24/2017 12:31 PM|111.222.333.217|111.222.333.217|SYS-5-CONFIG_I|72: 002391: Jun 24 12:31:10: %SYS-5-CONFIG_I: Configured from 10.1.0.100 by snmp
6/26/2017 1:24 PM|111.222.333.132|111.222.333.132|SYS-5-CONFIG_I|1223: 001257: Jun 26 13:24:57: %SYS-5-CONFIG_I: Configured from console by jsmith on vty0 (10.1.250.78)
6/26/2017 1:32 PM|111.222.333.133|111.222.333.133|SYS-5-CONFIG_I|59: 000078: .Jun 26 13:32:39: %SYS-5-CONFIG_I: Configured from console by jsmith on vty0 (10.1.250.78)
6/28/2017 7:33 AM|111.222.333.141|111.222.333.141|SYS-5-CONFIG_I|27032: 027035: Jun 28 07:33:12: %SYS-5-CONFIG_I: Configured from console by jsmith on vty0 (10.1.250.78)}
if DEMO [
    write CONFIG-LOG DEMO-DATA
]

;; [---------------------------------------------------------------------------]
;; [ These are some functions used for emitting the html code in the final     ]
;; [ report.                                                                   ]
;; [---------------------------------------------------------------------------]

;; [---------------------------------------------------------------------------]
;; [ Items set up by the caller.                                               ]
;; [---------------------------------------------------------------------------]

HTMLREP-FILE-ID: %htmlrep.html
HTMLREP-TITLE: " "
HTMLREP-PRE-STRING: " "
HTMLREP-POST-STRING: " "
HTMLREP-PROGRAM-NAME: " "
HTMLREP-CODE-BLOCK: " "

;; [---------------------------------------------------------------------------]
;; [ Internal working items.                                                   ]
;; [---------------------------------------------------------------------------]

HTMLREP-FILE-OPEN: false

;; [---------------------------------------------------------------------------]
;; [ This is the top of the html page.                                         ]
;; [---------------------------------------------------------------------------]

HTMLREP-PAGE-HEAD: {



 VPN logins 




Router Configuration Changes

} ;; [---------------------------------------------------------------------------] ;; [ This is the end of the html page. ] ;; [---------------------------------------------------------------------------] HTMLREP-PAGE-FOOT: {
} ;; [---------------------------------------------------------------------------] ;; [ This is the area where we will build up the html page in memory. ] ;; [---------------------------------------------------------------------------] HTMLREP-PAGE: make string! 5000 ;; [---------------------------------------------------------------------------] ;; [ This is the procedure to "open" the report. ] ;; [ The "build-markup" function will replace the placeholders in the html ] ;; [ with the values resulting from their evaluation. ] ;; [---------------------------------------------------------------------------] HTMLREP-OPEN: does [ HTMLREP-PAGE: copy "" append HTMLREP-PAGE build-markup HTMLREP-PAGE-HEAD append HTMLREP-PAGE newline HTMLREP-FILE-OPEN: true ] ;; [---------------------------------------------------------------------------] ;; [ This is the procedure to "close" the report. ] ;; [ It writes to disk the html page we have built up in memeory. ] ;; [---------------------------------------------------------------------------] HTMLREP-CLOSE: does [ append HTMLREP-PAGE build-markup HTMLREP-PAGE-FOOT append HTMLREP-PAGE newline write HTMLREP-FILE-ID HTMLREP-PAGE HTMLREP-FILE-OPEN: false ] ;; [---------------------------------------------------------------------------] ;; [ This procedure emits a row of an html table containing heading ] ;; [ elements supplied by the caller in a block of strings. ] ;; [---------------------------------------------------------------------------] HTMLREP-EMIT-HEAD: func [ "Emit a heading row with literals supplied in a block" HTMLREP-HEADING-BLOCK [block!] ] [ append HTMLREP-PAGE "" foreach HTMLREP-HEAD-LIT HTMLREP-HEADING-BLOCK [ append HTMLREP-PAGE {} append HTMLREP-PAGE HTMLREP-HEAD-LIT append HTMLREP-PAGE "" ] append HTMLREP-PAGE "" append HTMLREP-PAGE newline ] ;; [---------------------------------------------------------------------------] ;; [ This procedure emits a row of an html table containing the values of ] ;; [ words supplied by the caller in a block. ] ;; [ Note the requirement that the caller "reduce" the block passed to this ] ;; [ function so that we are getting values and not words. ] ;; [---------------------------------------------------------------------------] HTMLREP-EMIT-LINE: func [ "Emit a detail row with values supplied in a block" HTMLREP-DETAIL-BLOCK [block!] ] [ append HTMLREP-PAGE "" foreach HTMLREP-VALUE HTMLREP-DETAIL-BLOCK [ append HTMLREP-PAGE {} append HTMLREP-PAGE HTMLREP-VALUE append HTMLREP-PAGE "" ] append HTMLREP-PAGE "" append HTMLREP-PAGE newline ] ;; [---------------------------------------------------------------------------] ;; [ End of html functions. ] ;; [ Below is the operation performed by this program. ] ;; [---------------------------------------------------------------------------] ;; [---------------------------------------------------------------------------] ;; [ Data we will be working with. ] ;; [ We are going to display only a few lines, as many as will fit on a ] ;; [ monitor. ] ;; [---------------------------------------------------------------------------] CONFIG-LINES: [] WS-DATE: "" WS-SWITCH: "" WS-IP: "" WS-XXX: "" WS-USERID: "" WS-FROM: "" WS-START: 0 WS-STOP: 0 WS-LENGTH: 0 WS-COUNTER: 0 WS-PAGESIZE: 20 ;; [---------------------------------------------------------------------------] ;; [ Set up the output file. ] ;; [---------------------------------------------------------------------------] HTMLREP-FILE-ID: OUTPUT-FILE HTMLREP-TITLE: "Cisco Changes" HTMLREP-PROGRAM-NAME: "CiscoConfig.r" HTMLREP-OPEN HTMLREP-EMIT-HEAD [ "DATE-TIME" "SWITCH" "USERID" "FROM" ] ;; [---------------------------------------------------------------------------] ;; [ Bring the entire file into memory. ] ;; [---------------------------------------------------------------------------] CONFIG-LINES: read/lines CONFIG-LOG WS-LENGTH: length? CONFIG-LINES WS-STOP: WS-LENGTH if (WS-LENGTH <= WS-PAGESIZE) [ WS-START: 0 ] if (WS-LENGTH > WS-PAGESIZE) [ WS-START: (WS-STOP - WS-PAGESIZE) ] ;; [---------------------------------------------------------------------------] ;; [ Take apart each line and put the relevant data items in the output ] ;; [ report. ] ;; [---------------------------------------------------------------------------] ID-CHAR: charset "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" foreach LINE CONFIG-LINES [ WS-COUNTER: WS-COUNTER + 1 if (WS-COUNTER > WS-STOP) [ break ] WS-DATE: copy "" WS-SWITCH: copy "" WS-USERID: copy "" WS-FROM: copy "" if (WS-COUNTER > WS-START) [ set [WS-DATE WS-SWITCH WS-IP WS-XXX WS-MSG ] parse/all LINE "|" parse/all/case WS-MSG [ thru " by " copy WS-USERID some ID-CHAR thru "(" copy WS-FROM TO ")" ] HTMLREP-EMIT-LINE reduce [ WS-DATE WS-SWITCH WS-USERID WS-FROM ] ] ] attempt [HTMLREP-CLOSE] ;halt ;alert "Done."