diff --git a/lokiwriter.go b/lokiwriter.go new file mode 100644 index 0000000..b680119 --- /dev/null +++ b/lokiwriter.go @@ -0,0 +1,84 @@ +package meowlib + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "strings" + "time" +) + +type LokiWriter struct { + url string + labels map[string]string + httpClient *http.Client +} + +type LokiPayload struct { + Streams []LokiStream `json:"streams"` +} + +type LokiStream struct { + Labels string `json:"labels"` + Entries []LokiEntry `json:"entries"` +} + +type LokiEntry struct { + Timestamp string `json:"ts"` + Line string `json:"line"` +} + +func NewLokiWriter(url string, labels map[string]string) *LokiWriter { + return &LokiWriter{ + url: url, + labels: labels, + httpClient: &http.Client{}, + } +} + +func (w *LokiWriter) Write(p []byte) (n int, err error) { + // Format log entry for Loki + entry := LokiEntry{ + Timestamp: time.Now().Format(time.RFC3339Nano), + Line: string(p), + } + + labels := []string{} + for k, v := range w.labels { + labels = append(labels, fmt.Sprintf(`%s="%s"`, k, v)) + } + labelString := "{" + strings.Join(labels, ",") + "}" + + stream := LokiStream{ + Labels: labelString, + Entries: []LokiEntry{entry}, + } + + payload := LokiPayload{ + Streams: []LokiStream{stream}, + } + + payloadBytes, err := json.Marshal(payload) + if err != nil { + return 0, fmt.Errorf("failed to marshal payload: %w", err) + } + + req, err := http.NewRequest("POST", w.url, bytes.NewReader(payloadBytes)) + if err != nil { + return 0, fmt.Errorf("failed to create HTTP request: %w", err) + } + req.Header.Set("Content-Type", "application/json") + + resp, err := w.httpClient.Do(req) + if err != nil { + return 0, fmt.Errorf("failed to send log to Loki: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusNoContent { + return 0, fmt.Errorf("received non-204 response from Loki: %d", resp.StatusCode) + } + + return len(p), nil +} diff --git a/server/logger.go b/server/logger.go new file mode 100644 index 0000000..be5b6bb --- /dev/null +++ b/server/logger.go @@ -0,0 +1,12 @@ +package server + +import ( + "github.com/rs/zerolog" +) + +var logger zerolog.Logger + +// AddLogger sets the logger for the sublibrary +func AddLogger(l zerolog.Logger) { + logger = l +} diff --git a/server/router.go b/server/router.go index 849a41e..71d09b7 100644 --- a/server/router.go +++ b/server/router.go @@ -46,6 +46,7 @@ func (r *RedisRouter) Route(msg *meowlib.ToServerMessage) (*meowlib.FromServerMe } // user message => store if len(msg.Messages) > 0 { + logger.Info().Msg("storing message") from_server, err = r.storeMessage(msg) if err != nil { return nil, err @@ -53,11 +54,13 @@ func (r *RedisRouter) Route(msg *meowlib.ToServerMessage) (*meowlib.FromServerMe } // check for messages if len(msg.PullRequest) > 0 { + logger.Info().Msg("checking for messages") from_server, err = r.checkForMessage(msg) if err != nil { return nil, err } if msg.Timeout > 0 { + logger.Info().Msg("long poll, subscribing for messages") // set timeout for the lookup from_server, err = r.subscribe(msg, int(msg.Timeout)) if err != nil { @@ -67,6 +70,7 @@ func (r *RedisRouter) Route(msg *meowlib.ToServerMessage) (*meowlib.FromServerMe } // initiate video if msg.VideoData != nil { + logger.Info().Msg("handling video") from_server, err = r.handleVideo(msg) if err != nil { return nil, err @@ -74,6 +78,7 @@ func (r *RedisRouter) Route(msg *meowlib.ToServerMessage) (*meowlib.FromServerMe } // manage Matriochka if msg.MatriochkaMessage != nil { + logger.Info().Msg("handling matriochka") from_server, err = r.handleMatriochka(msg) if err != nil { return nil, err @@ -85,6 +90,7 @@ func (r *RedisRouter) Route(msg *meowlib.ToServerMessage) (*meowlib.FromServerMe } // Through server invitation process if msg.Invitation != nil { + logger.Info().Msg("handling invitation") from_server, err = r.handleInvitation(msg) if err != nil { return nil, err