Add gRPC observability: logging, metrics, recovery interceptors

This commit is contained in:
Alexander
2026-05-06 21:58:24 +02:00
parent 67f46f740b
commit 3249bdc35c
7 changed files with 170 additions and 15 deletions
+14 -5
View File
@@ -34,33 +34,42 @@ func (indexer *JacketIndexer) Search(query string, limit int32, tracker string)
url := indexer.cfg.Indexer.Url
uri := fmt.Sprintf("%v/api/v2.0/indexers/%v/results/torznab?apikey=%v&limit=%d&cat=3010,3040&q=%v&t=search", url, searchTracker, indexer.cfg.Indexer.ApiKey, limit, query)
log.Debug().Str("uri", uri).Msg("Sending search request")
log.Trace().Str("tracker", searchTracker).Str("query", query).Int32("limit", limit).Msg("jackett request")
req, err := http.NewRequest("GET", uri, nil)
if err != nil {
log.Error().Err(err).Msg("Error creating request")
log.Error().Err(err).Msg("error creating request")
return SearchResult{}, err
}
start := time.Now()
resp, err := indexer.client.Do(req)
if err != nil {
log.Error().Err(err).Msg("Error making search request")
log.Error().Err(err).Msg("error making search request")
return SearchResult{}, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Error().Err(err).Msg("Error reading search response body")
log.Error().Err(err).Msg("error reading search response body")
return SearchResult{}, err
}
log.Trace().
Int("status", resp.StatusCode).
Int("body_bytes", len(body)).
Dur("duration", time.Since(start)).
Msg("jackett response")
var searchResult SearchResult
if err := xml.Unmarshal(body, &searchResult); err != nil {
log.Error().Err(err).Msg("Error parsing search XML")
log.Error().Err(err).Msg("error parsing search XML")
return SearchResult{}, err
}
log.Trace().Int("items", len(searchResult.Items)).Msg("jackett XML parsed")
return searchResult, nil
}
+25 -3
View File
@@ -3,6 +3,8 @@ package indexer
import (
"encoding/xml"
"github.com/rs/zerolog/log"
pb "homelab.lan/music-agregator/gen/music_agregator/indexer/v1"
"homelab.lan/music-agregator/internal/tracker/rutracker"
)
@@ -46,8 +48,25 @@ var (
func (sr *SearchResult) ToProto() *pb.SearchResponse {
var pbItems []*pb.SearchItem
var skipped int
for _, item := range sr.Items {
release := rutrackerParserFactory.GetParser(item.Categories).Parse(item.Title)
log.Trace().
Str("tracker", item.JackettIndexer.ID).
Str("title", item.Title).
Str("artist", release.Artist).
Str("album", release.Album).
Int("year", release.Year).
Bool("parsed", release.ParsedSuccessfully).
Msg("parsed item")
if !release.ParsedSuccessfully {
skipped++
continue
}
pbAttrs := make([]*pb.TorznabAttr, len(item.TorznabAttrs))
for j, attr := range item.TorznabAttrs {
pbAttrs[j] = &pb.TorznabAttr{
@@ -56,9 +75,6 @@ func (sr *SearchResult) ToProto() *pb.SearchResponse {
}
}
// TODO add the check from what tracker the result is to properly get the parser and thus parse it
release := rutrackerParserFactory.GetParser(item.Categories).Parse(item.Title)
pbItems = append(pbItems, &pb.SearchItem{
Title: item.Title,
DownloadLink: item.Link,
@@ -77,6 +93,12 @@ func (sr *SearchResult) ToProto() *pb.SearchResponse {
})
}
log.Trace().
Int("total", len(sr.Items)).
Int("parsed", len(pbItems)).
Int("skipped", skipped).
Msg("conversion complete")
return &pb.SearchResponse{
Result: pbItems,
}
+26 -3
View File
@@ -26,13 +26,36 @@ func NewIndexerServer(cfg config.Config) (*IndexerServer, error) {
}
func (server *IndexerServer) Search(ctx context.Context, req *pb.SearchRequest) (*pb.SearchResponse, error) {
log.Debug().Str("query", req.GetQuery()).Int32("limit", req.GetLimit()).Str("indexer", req.GetTracker()).Msg("Running search with these prams")
log.Debug().
Str("query", req.GetQuery()).
Int32("limit", req.GetLimit()).
Str("tracker", req.GetTracker()).
Msg("search started")
return server.service.Search(req)
resp, err := server.service.Search(req)
if err != nil {
log.Error().Err(err).Str("query", req.GetQuery()).Msg("search failed")
return nil, err
}
log.Debug().
Str("query", req.GetQuery()).
Int("results", len(resp.GetResult())).
Msg("search completed")
return resp, nil
}
func (server *IndexerServer) Capabilities(ctx context.Context, req *pb.CapabilitiesRequest) (*pb.CapabilitiesResponse, error) {
return server.service.Capabilities(req)
log.Debug().Str("indexer", req.GetIndexer()).Msg("capabilities requested")
resp, err := server.service.Capabilities(req)
if err != nil {
log.Error().Err(err).Str("indexer", req.GetIndexer()).Msg("capabilities failed")
return nil, err
}
return resp, nil
}
func (s *IndexerServer) Register(server *grpc.Server) {
+6 -1
View File
@@ -24,11 +24,16 @@ func NewIndexerService(cfg config.Config) (*IndexerService, error) {
}
func (service *IndexerService) Search(req *pb.SearchRequest) (*pb.SearchResponse, error) {
log.Trace().Str("query", req.GetQuery()).Msg("fetching results from indexer")
searchResult, err := service.indexer.Search(req.GetQuery(), req.GetLimit(), req.GetTracker())
if err != nil {
log.Error().Err(err).Msg("Failed to search in indexer")
log.Error().Err(err).Msg("failed to search in indexer")
return nil, err
}
log.Trace().Int("raw_items", len(searchResult.Items)).Msg("indexer returned results, converting to proto")
return searchResult.ToProto(), nil
}