@@ -28,6 +28,7 @@ const TimeFormat = time.DateTime
2828var (
2929 tableColorNone = tablewriter.Colors {tablewriter .Normal }
3030 tableColorBold = tablewriter.Colors {tablewriter .Bold }
31+ tableColorRed = tablewriter.Colors {tablewriter .Bold , tablewriter .FgHiRedColor }
3132)
3233
3334type UAKeyType = unique.Handle [string ]
@@ -154,6 +155,7 @@ type AnalyzerConfig struct {
154155 PrefixV6 int
155156 PrintDelta SizeFlag
156157 RefreshSec int
158+ RepeatWarn time.Duration
157159 Server string
158160 SortBy SortByFlag
159161 Threshold SizeFlag
@@ -177,6 +179,7 @@ func (c *AnalyzerConfig) InstallFlags(flags *pflag.FlagSet, cmdname string) {
177179 flags .StringVarP (& c .Parser , "parser" , "p" , c .Parser , "Log parser (see \" ayano list parsers\" )" )
178180 flags .IntVar (& c .PrefixV4 , "prefixv4" , c .PrefixV4 , "Group IPv4 by prefix" )
179181 flags .IntVar (& c .PrefixV6 , "prefixv6" , c .PrefixV6 , "Group IPv6 by prefix" )
182+ flags .DurationVar (& c .RepeatWarn , "repeat-warn" , c .RepeatWarn , "Highlight repeated URL visits longer than duration" )
180183 flags .IntVarP (& c .RefreshSec , "refresh" , "r" , c .RefreshSec , "Refresh interval in seconds" )
181184 flags .StringVarP (& c .Server , "server" , "s" , c .Server , "Server IP to filter (nginx-json only)" )
182185 flags .VarP (& c .SortBy , "sort-by" , "S" , "Sort result by (size|requests)" )
@@ -269,7 +272,6 @@ func (a *Analyzer) RunLoop(iter fileiter.Iterator) error {
269272 break
270273 }
271274 if err := a .handleLine (line ); err != nil {
272- // TODO: replace with logger
273275 a .logger .Printf ("analyze error: %v" , err )
274276 }
275277 }
@@ -693,6 +695,7 @@ func (a *Analyzer) PrintTopValues(displayRecord map[netip.Prefix]time.Time, sort
693695 lastUpdateTime = HumanizeAgo (now .Sub (ipStats .LastURLUpdate ))
694696 lastAccessTime = HumanizeAgo (now .Sub (ipStats .LastURLAccess ))
695697 }
698+ isRepeatedVisit := a .Config .RepeatWarn != 0 && ipStats .LastURLAccess .Sub (ipStats .LastURLUpdate ) >= a .Config .RepeatWarn
696699
697700 average := total / uint64 (reqTotal )
698701 boldLine := false
@@ -708,11 +711,16 @@ func (a *Analyzer) PrintTopValues(displayRecord map[netip.Prefix]time.Time, sort
708711 }
709712 rowColors := slices .Repeat ([]tablewriter.Colors {tableColorNone }, len (row ))
710713 if boldLine {
714+ // Bold entire line
711715 rowColors = slices .Repeat ([]tablewriter.Colors {tableColorBold }, len (row ))
712716 } else {
713717 // Bold color for 2nd column (connections)
714718 rowColors [1 ] = tableColorBold
715719 }
720+ if isRepeatedVisit {
721+ // Bold+Red color for 8th column (lastAccessTime)
722+ rowColors [7 ] = tableColorRed
723+ }
716724
717725 if ! a .Config .NoNetstat {
718726 if _ , ok := activeConn [key .Prefix ]; ok {
0 commit comments