@@ -2,27 +2,37 @@ package logparser
2
2
3
3
import (
4
4
"fmt"
5
+ "log"
6
+ "math"
7
+ "os"
5
8
"regexp"
6
9
"strconv"
10
+ "strings"
7
11
"time"
8
12
9
13
"github.com/gomodule/redigo/redis"
14
+ "gonum.org/v1/plot"
15
+ "gonum.org/v1/plot/plotter"
16
+ "gonum.org/v1/plot/plotutil"
17
+ "gonum.org/v1/plot/vg"
10
18
)
11
19
12
20
// SshdParser Holds a struct that corresponds to a sshd log line
13
21
// and the redis connection
14
22
type SshdParser struct {
15
- r * redis.Conn
23
+ r1 * redis.Conn
24
+ r2 * redis.Conn
16
25
}
17
26
18
27
// Set set the redic connection to this parser
19
- func (s * SshdParser ) Set (rconn * redis.Conn ) {
20
- s .r = rconn
28
+ func (s * SshdParser ) Set (rconn1 * redis.Conn , rconn2 * redis.Conn ) {
29
+ s .r1 = rconn1
30
+ s .r2 = rconn2
21
31
}
22
32
23
33
// Parse parses a line of sshd log
24
34
func (s * SshdParser ) Parse (logline string ) error {
25
- r := * s .r
35
+ r := * s .r1
26
36
re := regexp .MustCompile (`^(?P<date>[[:alpha:]]{3}\s\d{2}\s\d{2}:\d{2}:\d{2}) (?P<host>[^ ]+) sshd\[[[:alnum:]]+\]: Invalid user (?P<username>[^ ]+) from (?P<src>.*$)` )
27
37
n1 := re .SubexpNames ()
28
38
r2 := re .FindAllStringSubmatch (logline , - 1 )[0 ]
@@ -73,5 +83,108 @@ func (s *SshdParser) Parse(logline string) error {
73
83
return err
74
84
}
75
85
86
+ // Keeping track of which days we updated statistics for
87
+ _ , err = redis .Int (r .Do ("SADD" , "toupdate" , fmt .Sprintf ("%v%v%v:statssrc" , parsedTime .Year (), int (parsedTime .Month ()), parsedTime .Day ())))
88
+ if err != nil {
89
+ r .Close ()
90
+ return err
91
+ }
92
+ _ , err = redis .Int (r .Do ("SADD" , "toupdate" , fmt .Sprintf ("%v%v%v:statsusername" , parsedTime .Year (), int (parsedTime .Month ()), parsedTime .Day ())))
93
+ if err != nil {
94
+ r .Close ()
95
+ return err
96
+ }
97
+ _ , err = redis .Int (r .Do ("SADD" , "toupdate" , fmt .Sprintf ("%v%v%v:statshost" , parsedTime .Year (), int (parsedTime .Month ()), parsedTime .Day ())))
98
+ if err != nil {
99
+ r .Close ()
100
+ return err
101
+ }
102
+
103
+ return nil
104
+ }
105
+
106
+ // Compile create graphs of the results
107
+ func (s * SshdParser ) Compile () error {
108
+ r := * s .r2
109
+
110
+ // Pulling statistics from database 1
111
+ if _ , err := r .Do ("SELECT" , 1 ); err != nil {
112
+ r .Close ()
113
+ return err
114
+ }
115
+
116
+ // List days for which we need to update statistic
117
+ toupdate , err := redis .Strings (r .Do ("SMEMBERS" , "toupdate" ))
118
+ if err != nil {
119
+ r .Close ()
120
+ return err
121
+ }
122
+
123
+ // Query statistics dor each day to update
124
+ for _ , v := range toupdate {
125
+ zrank , err := redis .Strings (r .Do ("ZRANGEBYSCORE" , v , "-inf" , "+inf" , "WITHSCORES" ))
126
+ if err != nil {
127
+ r .Close ()
128
+ return err
129
+ }
130
+
131
+ // Split keys and values - keep these ordered
132
+ values := plotter.Values {}
133
+ keys := make ([]string , 0 , len (zrank )/ 2 )
134
+
135
+ for k , v := range zrank {
136
+ // keys
137
+ if (k % 2 ) == 0 {
138
+ keys = append (keys , zrank [k ])
139
+ // values
140
+ } else {
141
+ fv , _ := strconv .ParseFloat (v , 64 )
142
+ values = append (values , fv )
143
+ }
144
+ }
145
+
146
+ p , err := plot .New ()
147
+ if err != nil {
148
+ panic (err )
149
+ }
150
+
151
+ stype := strings .Split (v , ":" )
152
+ switch stype [1 ] {
153
+ case "statsusername" :
154
+ p .Title .Text = "Usernames"
155
+ case "statssrc" :
156
+ p .Title .Text = "Source IP"
157
+ case "statshost" :
158
+ p .Title .Text = "Host"
159
+ default :
160
+ p .Title .Text = ""
161
+ log .Println ("We should not reach this point, open an issue." )
162
+ }
163
+
164
+ p .Y .Label .Text = "Count"
165
+ w := 0.5 * vg .Centimeter
166
+ bc , err := plotter .NewBarChart (values , w )
167
+ bc .Horizontal = true
168
+ if err != nil {
169
+ return err
170
+ }
171
+ bc .LineStyle .Width = vg .Length (0 )
172
+ bc .Color = plotutil .Color (0 )
173
+
174
+ p .Add (bc )
175
+ p .NominalY (keys ... )
176
+
177
+ // Create folder to store plots
178
+ if _ , err := os .Stat (stype [0 ]); os .IsNotExist (err ) {
179
+ os .Mkdir (stype [0 ], 0700 )
180
+ }
181
+
182
+ xsize := 3 + vg .Length (math .Round (float64 (len (keys )/ 2 )))
183
+ if err := p .Save (15 * vg .Centimeter , xsize * vg .Centimeter , fmt .Sprintf ("data/%v/%v.svg" , stype [0 ], v )); err != nil {
184
+ return err
185
+ }
186
+
187
+ }
188
+
76
189
return nil
77
190
}
0 commit comments