session_logger.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package sshlog
  2. import (
  3. "time"
  4. "github.com/cloudflare/cloudflared/logger"
  5. capnp "zombiezen.com/go/capnproto2"
  6. "zombiezen.com/go/capnproto2/pogs"
  7. )
  8. // SessionLogger will buffer and write events to disk using capnp proto for session replay
  9. type SessionLogger struct {
  10. logger *Logger
  11. encoder *capnp.Encoder
  12. }
  13. type sessionLogData struct {
  14. Timestamp string // The UTC timestamp of when the log occurred
  15. Content []byte // The shell output
  16. }
  17. // NewSessionLogger creates a new session logger by encapsulating a Logger object and writing capnp encoded messages to it
  18. func NewSessionLogger(filename string, logger logger.Service, flushInterval time.Duration, maxFileSize int64) (*SessionLogger, error) {
  19. l, err := NewLogger(filename, logger, flushInterval, maxFileSize)
  20. if err != nil {
  21. return nil, err
  22. }
  23. sessionLogger := &SessionLogger{
  24. logger: l,
  25. encoder: capnp.NewEncoder(l),
  26. }
  27. return sessionLogger, nil
  28. }
  29. // Writes to a log buffer. Implements the io.Writer interface.
  30. func (l *SessionLogger) Write(p []byte) (n int, err error) {
  31. return l.writeSessionLog(&sessionLogData{
  32. Timestamp: time.Now().UTC().Format(time.RFC3339),
  33. Content: p,
  34. })
  35. }
  36. // Close drains anything left in the buffer and cleans up any resources still
  37. // in use.
  38. func (l *SessionLogger) Close() error {
  39. return l.logger.Close()
  40. }
  41. func (l *SessionLogger) writeSessionLog(p *sessionLogData) (int, error) {
  42. msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
  43. if err != nil {
  44. return 0, err
  45. }
  46. log, err := NewRootSessionLog(seg)
  47. if err != nil {
  48. return 0, err
  49. }
  50. log.SetTimestamp(p.Timestamp)
  51. log.SetContent(p.Content)
  52. if err := l.encoder.Encode(msg); err != nil {
  53. return 0, err
  54. }
  55. return len(p.Content), nil
  56. }
  57. func unmarshalSessionLog(s SessionLog) (*sessionLogData, error) {
  58. p := new(sessionLogData)
  59. err := pogs.Extract(p, SessionLog_TypeID, s.Struct)
  60. return p, err
  61. }