redis.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. package tracing
  2. import (
  3. "bytes"
  4. "github.com/coroot/coroot-node-agent/ebpftracer"
  5. "go.opentelemetry.io/otel/attribute"
  6. "go.opentelemetry.io/otel/codes"
  7. semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
  8. "go.opentelemetry.io/otel/trace"
  9. "strconv"
  10. "time"
  11. )
  12. func handleRedisQuery(start, end time.Time, r *ebpftracer.L7Request, attrs []attribute.KeyValue) {
  13. cmd, args := parseRedis(r.Payload[:])
  14. if cmd == "" {
  15. return
  16. }
  17. _, span := tracer.Start(nil, cmd, trace.WithTimestamp(start), trace.WithSpanKind(trace.SpanKindClient))
  18. statement := cmd
  19. if args != "" {
  20. statement += " " + args
  21. }
  22. span.SetAttributes(append(attrs, semconv.DBSystemRedis, semconv.DBOperation(cmd), semconv.DBStatement(statement))...)
  23. if r.Status == 500 {
  24. span.SetStatus(codes.Error, "")
  25. }
  26. span.End(trace.WithTimestamp(end))
  27. }
  28. func parseRedis(payload []byte) (cmd string, args string) {
  29. var v, rest []byte
  30. var ok bool
  31. v, rest, ok = bytes.Cut(payload, crlf)
  32. if !ok || !bytes.HasPrefix(v, []byte("*")) {
  33. return
  34. }
  35. arrayLen, err := strconv.ParseUint(string(v[1:]), 10, 32)
  36. if err != nil {
  37. return
  38. }
  39. readString := func() string {
  40. v, rest, ok = bytes.Cut(rest, crlf)
  41. if !ok || !bytes.HasPrefix(v, []byte("$")) {
  42. return ""
  43. }
  44. v, rest, ok = bytes.Cut(rest, crlf)
  45. if ok {
  46. return string(v)
  47. }
  48. return ""
  49. }
  50. cmd = readString()
  51. if cmd == "" {
  52. return
  53. }
  54. if arrayLen > 1 {
  55. args = readString()
  56. if arrayLen > 2 {
  57. args += " ..."
  58. }
  59. }
  60. return
  61. }