github.com/grafana/pyroscope@v1.18.0/.cursor/rules/go-backend.mdc (about)

     1  ---
     2  description: Go backend coding standards and patterns for Pyroscope
     3  globs:
     4    - "**/*.go"
     5    - "!**/*_test.go"
     6  ---
     7  
     8  # Go Backend Development
     9  
    10  ## Import Organization
    11  
    12  Always organize imports into three groups separated by blank lines:
    13  
    14  ```go
    15  import (
    16      // Standard library
    17      "context"
    18      "fmt"
    19  
    20      // Third-party packages
    21      "github.com/prometheus/client_golang/prometheus"
    22      "go.uber.org/atomic"
    23  
    24      // Internal packages
    25      "github.com/grafana/pyroscope/pkg/model"
    26      "github.com/grafana/pyroscope/pkg/objstore"
    27  )
    28  ```
    29  
    30  **Don't** add imports within the three import groups (keep them separate).
    31  
    32  ## Formatting & Linting
    33  
    34  - Use `golangci-lint` (run via `make lint`)
    35  - gofmt for formatting
    36  - goimports with `-local github.com/grafana/pyroscope`
    37  - Enabled linters: depguard, goconst, misspell, revive, unconvert, unparam
    38  
    39  ## Logging
    40  
    41  - **Use**: `github.com/go-kit/log`
    42  - **Don't**: `github.com/go-kit/kit/log` (deprecated import path)
    43  - **Don't**: `fmt.Println` for logging
    44  
    45  Use structured logging:
    46  
    47  ```go
    48  import "github.com/go-kit/log/level"
    49  
    50  level.Error(logger).Log("msg", "failed to process", "err", err)
    51  level.Info(logger).Log("msg", "processing complete", "count", count)
    52  ```
    53  
    54  ## Error Handling
    55  
    56  - Always check errors explicitly
    57  - Wrap errors with context:
    58  
    59  ```go
    60  if err != nil {
    61      return fmt.Errorf("failed to query: %w", err)
    62  }
    63  ```
    64  
    65  ## Context Usage
    66  
    67  - Always pass `context.Context` as the first parameter
    68  - Respect context cancellation in loops and long operations:
    69  
    70  ```go
    71  func process(ctx context.Context, items []Item) error {
    72      for _, item := range items {
    73          select {
    74          case <-ctx.Done():
    75              return ctx.Err()
    76          default:
    77          }
    78          // process item
    79      }
    80      return nil
    81  }
    82  ```
    83  
    84  ## Multi-tenancy Pattern
    85  
    86  All requests must include a tenant ID. Extract from context:
    87  
    88  ```go
    89  import "github.com/grafana/pyroscope/pkg/tenant"
    90  
    91  tenantID, err := tenant.ExtractTenantIDFromContext(ctx)
    92  if err != nil {
    93      return err
    94  }
    95  ```
    96  
    97  **Never** hardcode tenant IDs.
    98  
    99  ## Object Storage Pattern
   100  
   101  Use the abstract Bucket interface:
   102  
   103  ```go
   104  import "github.com/grafana/pyroscope/pkg/objstore"
   105  
   106  bucket := objstore.NewBucket(cfg)
   107  reader, err := bucket.Get(ctx, "path/to/object")
   108  ```
   109  
   110  ## Configuration Pattern
   111  
   112  Use `github.com/grafana/dskit` for configuration:
   113  
   114  ```go
   115  type Config struct {
   116      ListenPort int `yaml:"listen_port"`
   117  }
   118  
   119  func (cfg *Config) RegisterFlags(f *flag.FlagSet) {
   120      f.IntVar(&cfg.ListenPort, "server.http-listen-port", 4040, "HTTP listen port")
   121  }
   122  ```
   123  
   124  ## Performance Considerations
   125  
   126  1. **Minimize Allocations in Hot Paths**:
   127     - Reuse buffers with `sync.Pool`
   128     - Avoid string concatenation in loops
   129     - Use `strings.Builder` for string building
   130  
   131  2. **Concurrency**:
   132     - Use worker pools for bounded concurrency
   133     - Prefer channels for coordination over mutexes when possible
   134     - Don't create unbounded goroutines - use worker pools or semaphores
   135  
   136  3. **Profile Your Changes**:
   137     ```bash
   138     go test -cpuprofile=cpu.prof -memprofile=mem.prof -bench=.
   139     go tool pprof cpu.prof
   140     ```
   141  
   142  ## Code Generation
   143  
   144  **IMPORTANT**: After changing protobuf, configs, or flags:
   145  ```bash
   146  make generate
   147  ```
   148  Commit the generated files with your changes.
   149  
   150  ## Security
   151  
   152  1. **Input Validation**: Always validate and sanitize user input
   153  2. **Path Traversal**: Validate object keys before storage operations
   154  3. **Rate Limiting**: Distributor implements per-tenant rate limiting