writer.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package logging
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "strings"
  7. "sync"
  8. "time"
  9. "github.com/charmbracelet/crush/internal/pubsub"
  10. "github.com/go-logfmt/logfmt"
  11. )
  12. const (
  13. persistKeyArg = "$_persist"
  14. PersistTimeArg = "$_persist_time"
  15. )
  16. type LogData struct {
  17. messages []LogMessage
  18. *pubsub.Broker[LogMessage]
  19. lock sync.Mutex
  20. }
  21. func (l *LogData) Add(msg LogMessage) {
  22. l.lock.Lock()
  23. defer l.lock.Unlock()
  24. l.messages = append(l.messages, msg)
  25. l.Publish(pubsub.CreatedEvent, msg)
  26. }
  27. func (l *LogData) List() []LogMessage {
  28. l.lock.Lock()
  29. defer l.lock.Unlock()
  30. return l.messages
  31. }
  32. var defaultLogData = &LogData{
  33. messages: make([]LogMessage, 0),
  34. Broker: pubsub.NewBroker[LogMessage](),
  35. }
  36. type writer struct{}
  37. func (w *writer) Write(p []byte) (int, error) {
  38. d := logfmt.NewDecoder(bytes.NewReader(p))
  39. for d.ScanRecord() {
  40. msg := LogMessage{
  41. ID: fmt.Sprintf("%d", time.Now().UnixNano()),
  42. Time: time.Now(),
  43. }
  44. for d.ScanKeyval() {
  45. switch string(d.Key()) {
  46. case "time":
  47. parsed, err := time.Parse(time.RFC3339, string(d.Value()))
  48. if err != nil {
  49. return 0, fmt.Errorf("parsing time: %w", err)
  50. }
  51. msg.Time = parsed
  52. case "level":
  53. msg.Level = strings.ToLower(string(d.Value()))
  54. case "msg":
  55. msg.Message = string(d.Value())
  56. default:
  57. if string(d.Key()) == persistKeyArg {
  58. msg.Persist = true
  59. } else if string(d.Key()) == PersistTimeArg {
  60. parsed, err := time.ParseDuration(string(d.Value()))
  61. if err != nil {
  62. continue
  63. }
  64. msg.PersistTime = parsed
  65. } else {
  66. msg.Attributes = append(msg.Attributes, Attr{
  67. Key: string(d.Key()),
  68. Value: string(d.Value()),
  69. })
  70. }
  71. }
  72. }
  73. defaultLogData.Add(msg)
  74. }
  75. if d.Err() != nil {
  76. return 0, d.Err()
  77. }
  78. return len(p), nil
  79. }
  80. func NewWriter() *writer {
  81. w := &writer{}
  82. return w
  83. }
  84. func Subscribe(ctx context.Context) <-chan pubsub.Event[LogMessage] {
  85. return defaultLogData.Subscribe(ctx)
  86. }
  87. func List() []LogMessage {
  88. return defaultLogData.List()
  89. }