mirror of https://github.com/curusarn/resh
Session watcher recieves all incoming records and and periodically checks if the session is still running. If session exits it sends message to other parts of RESH to drop the session. History handler recieves sessions to drop from session watcher.pull/18/head
parent
77d94c9e12
commit
dc1d5e4848
@ -1,57 +0,0 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"log" |
||||
"os" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
) |
||||
|
||||
// HistfileWriter - reads records from channel, merges them and wrotes them to file
|
||||
func HistfileWriter(input chan records.Record, outputPath string) { |
||||
sessions := map[string]records.Record{} |
||||
|
||||
for { |
||||
record := <-input |
||||
if record.PartOne { |
||||
if _, found := sessions[record.SessionID]; found { |
||||
log.Println("ERROR: Got another first part of the records before merging the previous one - overwriting!") |
||||
} |
||||
sessions[record.SessionID] = record |
||||
} else { |
||||
part1, found := sessions[record.SessionID] |
||||
if found == false { |
||||
log.Println("ERROR: Got second part of records and nothing to merge it with - ignoring!") |
||||
continue |
||||
} |
||||
delete(sessions, record.SessionID) |
||||
go mergeAndWriteRecord(part1, record, outputPath) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func mergeAndWriteRecord(part1, part2 records.Record, outputPath string) { |
||||
err := part1.Merge(part2) |
||||
if err != nil { |
||||
log.Println("Error while merging", err) |
||||
return |
||||
} |
||||
recJSON, err := json.Marshal(part1) |
||||
if err != nil { |
||||
log.Println("Marshalling error", err) |
||||
return |
||||
} |
||||
f, err := os.OpenFile(outputPath, |
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
||||
if err != nil { |
||||
log.Println("Could not open file", err) |
||||
return |
||||
} |
||||
defer f.Close() |
||||
_, err = f.Write(append(recJSON, []byte("\n")...)) |
||||
if err != nil { |
||||
log.Printf("Error while writing: %v, %s\n", part1, err) |
||||
return |
||||
} |
||||
} |
||||
@ -0,0 +1,97 @@ |
||||
package histfile |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"log" |
||||
"os" |
||||
"sync" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
) |
||||
|
||||
type histfile struct { |
||||
mutex sync.Mutex |
||||
sessions map[string]records.Record |
||||
outputPath string |
||||
} |
||||
|
||||
// Go creates histfile and runs two gorutines on it
|
||||
func Go(input chan records.Record, outputPath string, sessionsToDrop chan string) { |
||||
hf := histfile{sessions: map[string]records.Record{}, outputPath: outputPath} |
||||
go hf.writer(input) |
||||
go hf.sessionGC(sessionsToDrop) |
||||
} |
||||
|
||||
// sessionGC reads sessionIDs from channel and deletes them from histfile struct
|
||||
func (h *histfile) sessionGC(sessionsToDrop chan string) { |
||||
for { |
||||
func() { |
||||
session := <-sessionsToDrop |
||||
log.Println("histfile: got session to drop", session) |
||||
h.mutex.Lock() |
||||
defer h.mutex.Unlock() |
||||
if part1, found := h.sessions[session]; found == true { |
||||
log.Println("histfile: Dropping session:", session) |
||||
delete(h.sessions, session) |
||||
go writeRecord(part1, h.outputPath) |
||||
} else { |
||||
log.Println("histfile: No hanging parts for session:", session) |
||||
} |
||||
}() |
||||
} |
||||
} |
||||
|
||||
// writer reads records from channel, merges them and writes them to file
|
||||
func (h *histfile) writer(input chan records.Record) { |
||||
for { |
||||
func() { |
||||
record := <-input |
||||
h.mutex.Lock() |
||||
defer h.mutex.Unlock() |
||||
|
||||
if record.PartOne { |
||||
if _, found := h.sessions[record.SessionID]; found { |
||||
log.Println("histfile ERROR: Got another first part of the records before merging the previous one - overwriting!") |
||||
} |
||||
h.sessions[record.SessionID] = record |
||||
} else { |
||||
part1, found := h.sessions[record.SessionID] |
||||
if found == false { |
||||
log.Println("histfile ERROR: Got second part of records and nothing to merge it with - ignoring!") |
||||
} else { |
||||
delete(h.sessions, record.SessionID) |
||||
go mergeAndWriteRecord(part1, record, h.outputPath) |
||||
} |
||||
} |
||||
}() |
||||
} |
||||
} |
||||
|
||||
func mergeAndWriteRecord(part1, part2 records.Record, outputPath string) { |
||||
err := part1.Merge(part2) |
||||
if err != nil { |
||||
log.Println("Error while merging", err) |
||||
return |
||||
} |
||||
writeRecord(part1, outputPath) |
||||
} |
||||
|
||||
func writeRecord(rec records.Record, outputPath string) { |
||||
recJSON, err := json.Marshal(rec) |
||||
if err != nil { |
||||
log.Println("Marshalling error", err) |
||||
return |
||||
} |
||||
f, err := os.OpenFile(outputPath, |
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
||||
if err != nil { |
||||
log.Println("Could not open file", err) |
||||
return |
||||
} |
||||
defer f.Close() |
||||
_, err = f.Write(append(recJSON, []byte("\n")...)) |
||||
if err != nil { |
||||
log.Printf("Error while writing: %v, %s\n", rec, err) |
||||
return |
||||
} |
||||
} |
||||
@ -0,0 +1,69 @@ |
||||
package sesswatch |
||||
|
||||
import ( |
||||
"log" |
||||
"sync" |
||||
"time" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
"github.com/mitchellh/go-ps" |
||||
) |
||||
|
||||
type sesswatch struct { |
||||
sessionsToDrop []chan string |
||||
sleepSeconds uint |
||||
|
||||
watchedSessions map[string]bool |
||||
mutex sync.Mutex |
||||
} |
||||
|
||||
// Go runs the session watcher - watches sessions and sends
|
||||
func Go(input chan records.Record, sessionsToDrop []chan string, sleepSeconds uint) { |
||||
sw := sesswatch{sessionsToDrop: sessionsToDrop, sleepSeconds: sleepSeconds, watchedSessions: map[string]bool{}} |
||||
go sw.waiter(input) |
||||
} |
||||
|
||||
func (s *sesswatch) waiter(sessionsToWatch chan records.Record) { |
||||
for { |
||||
func() { |
||||
record := <-sessionsToWatch |
||||
session := record.SessionID |
||||
pid := record.SessionPid |
||||
if record.PartOne == false { |
||||
log.Println("sesswatch: part2 - ignoring:", session, "~", pid) |
||||
return // continue
|
||||
} |
||||
log.Println("sesswatch: got session ~ pid:", session, "~", pid) |
||||
s.mutex.Lock() |
||||
defer s.mutex.Unlock() |
||||
if s.watchedSessions[session] == false { |
||||
log.Println("sesswatch: start watching NEW session ~ pid:", session, "~", pid) |
||||
s.watchedSessions[session] = true |
||||
go s.watcher(session, record.SessionPid) |
||||
} |
||||
}() |
||||
} |
||||
} |
||||
|
||||
func (s *sesswatch) watcher(sessionID string, sessionPID int) { |
||||
for { |
||||
time.Sleep(time.Duration(s.sleepSeconds) * time.Second) |
||||
proc, err := ps.FindProcess(sessionPID) |
||||
if err != nil { |
||||
log.Println("sesswatch ERROR: error while finding process:", sessionPID) |
||||
} else if proc == nil { |
||||
log.Println("sesswatch: Dropping session ~ pid:", sessionID, "~", sessionPID) |
||||
func() { |
||||
s.mutex.Lock() |
||||
defer s.mutex.Unlock() |
||||
s.watchedSessions[sessionID] = false |
||||
}() |
||||
for _, ch := range s.sessionsToDrop { |
||||
log.Println("sesswatch: sending 'drop session' message ...") |
||||
ch <- sessionID |
||||
log.Println("sesswatch: sending 'drop session' message DONE") |
||||
} |
||||
break |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue