Skip to content

feat: pyroscope integrate - #2475

Merged
Calcium-Ion merged 5 commits into
QuantumNous:mainfrom
seefs001:feature/pyro
Dec 25, 2025
Merged

feat: pyroscope integrate#2475
Calcium-Ion merged 5 commits into
QuantumNous:mainfrom
seefs001:feature/pyro

Conversation

@seefs001

@seefs001 seefs001 commented Dec 19, 2025

Copy link
Copy Markdown
Collaborator

增加 pyroscope 集成,方便进行性能瓶颈排查
image

Summary by CodeRabbit

  • Chores
    • Added optional remote profiling/tracing integration that can be enabled via environment variables; startup will log errors but continue if profiling cannot be started.
  • Documentation
    • Documented new environment variables and added examples for configuring the profiling/tracing integration and hostname tag in README files and .env.example.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Dec 19, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds Pyroscope integration: new StartPyroScope() reads PYROSCOPE_* and HOSTNAME env vars and conditionally starts Pyroscope profiling; main.go invokes it during startup and logs any error without halting initialization. Documentation and go.mod updated to include Pyroscope config and dependency.

Changes

Cohort / File(s) Summary
Pyroscope Initialization
common/pyro.go
New file implementing StartPyroScope() which reads PYROSCOPE_URL, PYROSCOPE_APP_NAME, PYROSCOPE_BASIC_AUTH_USER, PYROSCOPE_BASIC_AUTH_PASSWORD, PYROSCOPE_MUTEX_RATE, PYROSCOPE_BLOCK_RATE, and HOSTNAME; when PYROSCOPE_URL is set it configures profiling types (CPU, allocations, in-use, goroutines, mutex, block), applies hostname tag, sets mutex/block profiling rates, starts pyroscope, and returns any start error.
Startup Integration
main.go
Calls common.StartPyroScope() after pprof enablement; logs returned errors as a SysError and continues server initialization.
Dependency Management
go.mod
Adds github.com/grafana/pyroscope-go v1.2.7 and related indirect deps; removes an indirect github.com/google/go-cmp entry.
Docs / Env
.env.example, README.md, README.en.md, README.fr.md, README.ja.md
Adds Pyroscope-related environment variables to docs and examples: PYROSCOPE_URL, PYROSCOPE_APP_NAME, PYROSCOPE_BASIC_AUTH_USER, PYROSCOPE_BASIC_AUTH_PASSWORD, PYROSCOPE_MUTEX_RATE, PYROSCOPE_BLOCK_RATE, and HOSTNAME with descriptions/defaults.

Sequence Diagram(s)

sequenceDiagram
    participant Main as main.go (startup)
    participant Pyro as common/pyro.go
    participant Env as Env Vars
    participant Server as Pyroscope Server

    Main->>Pyro: call StartPyroScope()
    Pyro->>Env: read PYROSCOPE_URL, APP_NAME,\nBASIC_AUTH_USER, BASIC_AUTH_PASSWORD,\nMUTEX_RATE, BLOCK_RATE, HOSTNAME
    alt PYROSCOPE_URL empty
        Pyro-->>Main: return nil (no-op)
    else PYROSCOPE_URL set
        Pyro->>Pyro: configure profiling types, tags\n(set mutex/block rates)
        Pyro->>Server: pyroscope.Start(config + auth)
        alt Start succeeds
            Server-->>Pyro: started
            Pyro-->>Main: return nil
        else Start fails
            Server-->>Pyro: error
            Pyro-->>Main: return error
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I twitch my whiskers, sniff the trace,
Pyroscope hums in a tidy space,
Goroutines pirouette, mutexes chime,
I hop and log each profiling time,
A carrot cheer for every runtime rhyme 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: pyroscope integrate' directly reflects the main change - adding Pyroscope integration for performance profiling. However, it uses slightly awkward phrasing ('integrate' instead of 'integration') and is somewhat generic.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
common/pyro.go (3)

28-28: Consider enabling Pyroscope client logging.

The logger is set to nil, which will suppress all Pyroscope client logs. This could make troubleshooting profiler initialization or connectivity issues difficult.

Consider providing a configurable logger or at least documenting why logging is disabled.


32-44: Document performance impact of comprehensive profiling.

All 10 profile types are enabled, including multiple memory profiles (alloc objects/space, inuse objects/space) and both mutex/block count and duration. This comprehensive profiling may introduce measurable overhead in production.

Consider:

  1. Documenting the expected performance impact
  2. Making profile types configurable via environment variable
  3. Providing preset configurations (e.g., "minimal", "standard", "comprehensive")

23-50: Consider capturing the profiler for graceful shutdown.

The profiler instance returned by pyroscope.Start is discarded. Capturing and exposing it would enable graceful shutdown when the application terminates.

🔎 Suggested improvement

The profiler instance can be captured to enable graceful shutdown. As shown in the Grafana documentation, calling profiler.Stop() ensures the last profile is sent before the application exits.

Example enhancement:

// Store the profiler globally for shutdown
var pyroscopeProfiler *pyroscope.Profiler

func StartPyroScope() error {
	// ... existing config code ...
	
	profiler, err := pyroscope.Start(pyroscope.Config{
		// ... existing config ...
	})
	if err != nil {
		return err
	}
	pyroscopeProfiler = profiler
	return nil
}

func StopPyroScope() {
	if pyroscopeProfiler != nil {
		_ = pyroscopeProfiler.Stop()
	}
}

Then call StopPyroScope() in a defer or shutdown handler in main.go.

main.go (1)

127-130: LGTM with a suggestion!

The placement and error handling are appropriate:

  • Initialized after pprof but before the HTTP server
  • Errors are logged without interrupting startup, treating profiling as optional

However, consider adding a deferred call to stop the profiler gracefully on shutdown to ensure the final profiling data is flushed to the server.

🔎 Optional enhancement for graceful shutdown

Add a deferred shutdown call near the existing database cleanup:

 	defer func() {
 		err := model.CloseDB()
 		if err != nil {
 			common.FatalLog("failed to close database: " + err.Error())
 		}
+		common.StopPyroScope()
 	}()

This requires implementing StopPyroScope() in common/pyro.go as suggested in the previous comment.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a98aad2 and 1168ddf.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • common/pyro.go (1 hunks)
  • go.mod (3 hunks)
  • main.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
common/pyro.go (2)
common/limiter/limiter.go (1)
  • Config (72-76)
setting/system_setting/system_setting_old.go (1)
  • ServerAddress (3-3)
main.go (2)
common/pyro.go (1)
  • StartPyroScope (9-50)
common/sys_log.go (1)
  • SysError (16-19)
🔇 Additional comments (2)
common/pyro.go (1)

9-14: LGTM!

The conditional initialization pattern is appropriate—returning nil when PYROSCOPE_URL is not set allows the profiler to be optional.

go.mod (1)

30-30: The dependency github.com/grafana/pyroscope-go v1.2.7 is actively used in the current Grafana Pyroscope server and no known security vulnerabilities have been found for this version. The library is maintained by Grafana and appears current. No further action required unless a security advisory emerges.

Comment thread common/pyro.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
common/pyro.go (1)

21-24: Profiling rates configuration already flagged.

The hardcoded mutex and block profiling rates have already been reviewed in previous comments. See the existing suggestion to make these configurable via environment variables.

🧹 Nitpick comments (2)
common/pyro.go (2)

17-18: Consider validating Basic Auth credentials are provided together.

If PYROSCOPE_BASIC_AUTH_USER is set without PYROSCOPE_BASIC_AUTH_PASSWORD (or vice versa), the Pyroscope client may behave unexpectedly. Consider logging a warning if only one credential is provided.

🔎 Optional validation logic
 	pyroscopeBasicAuthUser := GetEnvOrDefaultString("PYROSCOPE_BASIC_AUTH_USER", "")
 	pyroscopeBasicAuthPassword := GetEnvOrDefaultString("PYROSCOPE_BASIC_AUTH_PASSWORD", "")
+	
+	// Warn if credentials are partially configured
+	if (pyroscopeBasicAuthUser != "" && pyroscopeBasicAuthPassword == "") ||
+	   (pyroscopeBasicAuthUser == "" && pyroscopeBasicAuthPassword != "") {
+		SysLog("Pyroscope: Basic auth credentials partially configured - both user and password should be set")
+	}
 	pyroscopeHostname := GetEnvOrDefaultString("HOSTNAME", "new-api")

33-33: Consider enabling Pyroscope client logging for better observability.

Setting Logger: nil prevents visibility into Pyroscope client operations. If profiling fails or encounters issues, debugging will be difficult. Consider using a structured logger to capture Pyroscope client events.

🔎 Example with basic logging
+	// Create a simple logger that writes to SysLog
+	pyroscopeLogger := &pyroscopeLogAdapter{} // implement pyroscope.Logger interface
+
 	_, err := pyroscope.Start(pyroscope.Config{
 		ApplicationName: pyroscopeAppName,
 
 		ServerAddress:     pyroscopeUrl,
 		BasicAuthUser:     pyroscopeBasicAuthUser,
 		BasicAuthPassword: pyroscopeBasicAuthPassword,
 
-		Logger: nil,
+		Logger: pyroscopeLogger,
 
 		Tags: map[string]string{"hostname": pyroscopeHostname},
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1168ddf and 5ef7247.

📒 Files selected for processing (6)
  • .env.example (1 hunks)
  • README.en.md (1 hunks)
  • README.fr.md (1 hunks)
  • README.ja.md (1 hunks)
  • README.md (1 hunks)
  • common/pyro.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
common/pyro.go (2)
common/limiter/limiter.go (1)
  • Config (72-76)
setting/system_setting/system_setting_old.go (1)
  • ServerAddress (3-3)
🔇 Additional comments (7)
.env.example (1)

12-17: LGTM!

The Pyroscope configuration section is well-documented with appropriate example values. The variables align with the implementation in common/pyro.go.

README.en.md (1)

310-314: LGTM!

The Pyroscope environment variables are well-documented with clear descriptions and appropriate default values. The documentation aligns with the implementation.

README.md (1)

311-315: LGTM!

The Pyroscope environment variables are properly documented in Chinese with consistent descriptions and defaults matching the English version.

README.fr.md (1)

306-310: LGTM!

The French documentation for Pyroscope environment variables is consistent with other language versions and accurately reflects the implementation.

common/pyro.go (2)

11-14: LGTM!

The early return when PYROSCOPE_URL is empty is a clean pattern that prevents unnecessary initialization when Pyroscope is not configured.


37-49: Verify comprehensive profiling is appropriate for production.

All available profile types are enabled, including CPU, memory (alloc/inuse), goroutines, mutex, and block profiling. This provides comprehensive visibility but introduces runtime overhead, especially for mutex and block profiling.

Confirm this is intentional for production deployments. Consider making profile types configurable if users need to reduce overhead.

For reference, the enabled profiles include:

  • CPU: Samples execution time
  • Memory: Tracks allocations and in-use objects/space
  • Goroutines: Tracks goroutine counts
  • Mutex: Samples contention events (with rate 1/5)
  • Block: Samples blocking events (≥5ns threshold)

The mutex and block profiling can be particularly expensive under high contention.

README.ja.md (1)

315-319: LGTM!

The Japanese documentation for Pyroscope environment variables is consistent with other language versions and accurately documents the implementation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
common/pyro.go (2)

27-37: Consider using application logger instead of nil.

The Pyroscope configuration is correctly structured. However, setting Logger: nil means you won't see any Pyroscope client logs. Consider integrating with your application's logger for better observability during troubleshooting.

💡 Optional enhancement

If you have a logger instance available in the common package, you could integrate it:

-		Logger: nil,
+		Logger: pyroscope.StandardLogger, // or wrap your app logger

Alternatively, you can keep nil to avoid log noise in production.


52-56: Consider simplifying the return statement.

The error handling is correct. The profiler instance is intentionally discarded since Pyroscope manages the lifecycle internally.

💡 Minor simplification
 	})
-	if err != nil {
-		return err
-	}
-	return nil
+	return err
 }

This achieves the same result with fewer lines.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ef7247 and 531dfb2.

📒 Files selected for processing (6)
  • .env.example (1 hunks)
  • README.en.md (1 hunks)
  • README.fr.md (1 hunks)
  • README.ja.md (1 hunks)
  • README.md (1 hunks)
  • common/pyro.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • README.en.md
  • README.md
  • README.fr.md
  • .env.example
  • README.ja.md
🧰 Additional context used
🧬 Code graph analysis (1)
common/pyro.go (2)
common/limiter/limiter.go (1)
  • Config (72-76)
setting/system_setting/system_setting_old.go (1)
  • ServerAddress (3-3)
🔇 Additional comments (4)
common/pyro.go (4)

9-14: LGTM! Clean early return pattern.

The early return when PYROSCOPE_URL is empty gracefully disables profiling without error, which is the appropriate behavior.


24-25: Configuration looks correct, pending type verification.

The runtime profiling configuration is correct, assuming the types from lines 21-22 are verified. Making these rates configurable via environment variables (as implemented) addresses the previous review feedback about hardcoded values.


38-50: Excellent profile type coverage!

The profile types list is comprehensive and includes all essential profiling dimensions (CPU, memory allocations, goroutines, mutex/block contention). This will provide thorough performance insights.


21-22: No changes needed. The GetEnvOrDefault function already handles integer types correctly with the signature func GetEnvOrDefault(env string, defaultValue int) int, properly parsing the environment variable using strconv.Atoi() and returning an int. Lines 21-22 use this function correctly, and the returned values are compatible with runtime.SetMutexProfileFraction and runtime.SetBlockProfileRate, both of which expect int parameters.

Likely an incorrect or invalid review comment.

@seefs001
seefs001 marked this pull request as ready for review December 19, 2025 15:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
README.fr.md (1)

307-313: Align French punctuation conventions in environment variable descriptions.

The static analysis tool suggests using en-dashes (–) instead of hyphens (-) for empty default values in the French documentation table, which aligns with French typography conventions. Consider reviewing the punctuation formatting for consistency with the rest of the French README.

As per LanguageTool hints, lines ~307, ~309, and ~310 may need punctuation adjustments. Please review French typography standards for your documentation to ensure consistency.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 531dfb2 and da1b51a.

📒 Files selected for processing (4)
  • README.en.md
  • README.fr.md
  • README.ja.md
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • README.ja.md
  • README.en.md
🧰 Additional context used
🪛 LanguageTool
README.fr.md

[grammar] ~307-~307: Envisagez un remplacement
Context: ... | PYROSCOPE_URL | Adresse du serveur Pyroscope | - | | PYROSCOPE_APP_NAME | Nom de l'appli...

(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_DASH_–)


[grammar] ~309-~309: Envisagez un remplacement
Context: ...SIC_AUTH_USER| Utilisateur Basic Auth Pyroscope | - | |PYROSCOPE_BASIC_AUTH_PASSWORD` | Mot...

(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_DASH_–)


[grammar] ~310-~310: Envisagez un remplacement
Context: ...UTH_PASSWORD| Mot de passe Basic Auth Pyroscope | - | |PYROSCOPE_MUTEX_RATE` | Taux d'échan...

(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION_DASH_–)


[grammar] ~311-~311: Envisagez de supprimer «  | hostname | nom d’hôte tagué pour pyroscope | new-api  » 
Context: ...échantillonnage mutex Pyroscope | 5 | | PYROSCOPE_BLOCK_RATE | Taux d'échantillonnage block Pyroscope | 5 | | HOSTNAME | Nom d'hôte tagué pour Pyroscope | new-api | 📖 Configuration complète: [Document...

(QB_NEW_FR_OTHER_ERROR_IDS_UNNECESSARY_OTHER)

🔇 Additional comments (1)
README.md (1)

312-318: LGTM! Comprehensive Pyroscope environment variable documentation.

The environment variable documentation for Pyroscope integration is well-structured, complete, and clearly describes each configuration option. Default values are properly specified where applicable (PYROSCOPE_APP_NAME and HOSTNAME default to "new-api"; sampling rates default to 5).

@Calcium-Ion
Calcium-Ion merged commit 97b0268 into QuantumNous:main Dec 25, 2025
1 check passed
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants