1
0
Fork 0
mirror of https://github.com/alice-lg/birdwatcher.git synced 2025-03-09 00:00:05 +01:00

A configuration file describing a small state machine with chaining

regexps. We currently don't do anything with the matching fields,
though.
This commit is contained in:
Michael Cardell Widerkrantz 2016-10-23 14:02:34 +02:00
parent f331b7c350
commit 74cf806e6c
4 changed files with 187 additions and 2 deletions

View file

@ -1,12 +1,115 @@
package main
import (
"github.com/julienschmidt/httprouter"
"flag"
"fmt"
"io/ioutil"
"log"
"log/syslog"
"net/http"
"os"
"regexp"
"github.com/julienschmidt/httprouter"
yaml "gopkg.in/yaml.v2"
)
var debug int = 0
var slog *syslog.Writer // Our syslog connection
var conf Config
type Match struct {
Expr string // The regular expression as a string.
Fields []string // The named fields for grouped expressions.
Next string // The next regular expression in the flow.
}
// Compiled regular expression and it's corresponding match data.
type RE struct {
RE *regexp.Regexp
Match Match
}
// The configuration found in the configuration file.
type FileConfig struct {
Matches map[string]Match // All our regular expressions and related data.
Listen string // Listen to this address:port for HTTP.
FileName string // File to look for patterns
}
type Config struct {
Conf FileConfig
Res map[string]RE
}
// Parse the configuration file. Returns the configuration.
func parseconfig(filename string) (conf *Config, err error) {
conf = new(Config)
contents, err := ioutil.ReadFile(filename)
if err != nil {
return
}
fileconf := new(FileConfig)
if err = yaml.Unmarshal(contents, &fileconf); err != nil {
return
}
conf.Res = make(map[string]RE)
// Build the regexps from the configuration.
for key, match := range fileconf.Matches {
var err error
var re RE
re.Match = match
re.RE, err = regexp.Compile(match.Expr)
if err != nil {
slog.Err("Couldn't compile re: " + match.Expr)
os.Exit(-1)
}
// Check that the number of capturing groups matches the number of expected fields.
lengroups := len(re.RE.SubexpNames()) - 1
lenfields := len(re.Match.Fields)
if lengroups != lenfields {
line := fmt.Sprintf("Number of capturing groups (%v) not equal to number of fields (%v): %s", lengroups, lenfields, re.Match.Expr)
slog.Err(line)
os.Exit(-1)
}
conf.Res[key] = re
}
return
}
func main() {
var configfile = flag.String("config", "birdwatcher.yaml", "Path to configuration file")
var flagdebug = flag.Int("debug", 0, "Be more verbose")
flag.Parse()
debug = *flagdebug
slog, err := syslog.New(syslog.LOG_ERR, "birdwatcher")
if err != nil {
fmt.Printf("Couldn't open syslog")
os.Exit(-1)
}
slog.Debug("birdwatcher starting")
conf, err := parseconfig(*configfile)
if err != nil {
slog.Err("Couldn't parse configuration file: " + err.Error())
os.Exit(-1)
}
fmt.Printf("%v\n", conf)
r := httprouter.New()
r.GET("/status", Status)
r.GET("/routes", Routes)

28
birdwatcher.yaml Normal file
View file

@ -0,0 +1,28 @@
---
filename: v4-show-protocols-all.txt
# A map of all the expected patterns.
# fields: A list of variables to set from the grouped patterns.
# expr: The regular expression.
# next: The next regexp to go to after the current one has a match. ""
# if we are finished.
# action: What to do with the stored values.
matches:
# pp_0236_as10310 Pipe master up 2016-07-22 => t_0236_as10310
getprotocol:
fields:
- name
- prot
- date
- status
expr: "^([A-Z][a-z][0-9]*) (.*) .* (.*) (.*)"
next: "protdescription"
# Description: Pipe for AS10310 - Yahoo! - VLAN Interface 236
protdescription:
fields:
- desc
expr: " Description: (.*)"
next: ""

46
patterns.go Normal file
View file

@ -0,0 +1,46 @@
package main
import (
"bufio"
"fmt"
"os"
)
// readLines reads a whole file into memory
// and returns a slice of its lines.
func readLines(path string) ([]string, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
// pattern looks for pattern matching regular expression re in the
// lines buffer. Returns the name of our next regular expression to
// look for.
func pattern(re RE, lines []string) (next string) {
for _, line := range lines {
if debug > 1 {
slog.Debug("Looking at: " + line)
}
fields := re.RE.FindStringSubmatch(line)
if len(fields)-1 == len(re.Match.Fields) {
if debug > 0 {
line := fmt.Sprintf("Found match for a message of type '%v'", re.Match)
slog.Debug(line)
}
}
}
return re.Match.Next
}

View file

@ -2,10 +2,18 @@ package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Protocols(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprint(w, "protocols\n")
lines, err := readLines(conf.Conf.FileName)
if err != nil {
return
}
pattern(conf.Res["getprotocol"], lines)
}