Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: pika exporter error output due to versions dismatch #2951

Merged
merged 3 commits into from
Nov 18, 2024

Conversation

buzhimingyonghu
Copy link
Contributor

@buzhimingyonghu buzhimingyonghu commented Nov 13, 2024

问题描述:

由于不同的版本字段不同,导致一直触发log

image
image

解决方案:

根据不同的版本,增加对应的处理方式

提取info种的version,根据version选择不同的版本

	parseOpt := metrics.ParseOption{
		Version:        version,
		Extracts:       extracts,
		Info:           info,
		CurrentVersion: selectversion(version.Original()),
	}
func selectversion(version string) metrics.VersionChecker {
	var v metrics.VersionChecker

	switch version {
	case "3.3.6":
		v = &metrics.VersionChecker336{}
	case "3.5.5":
		v = &metrics.VersionChecker355{}
	case "3.5.0":
		v = &metrics.VersionChecker350{}
	default:
		return nil
	}
	return v
}

定义抽象接口,实现对多版本的控制。

type VersionChecker interface {
	CheckContainsEmptyValueName(key string) bool
	CheckContainsEmptyRegexName(key string) bool
}
type VersionChecker336 struct {
	EmptyValueName []string
	EmptyRegexName []string
}
type VersionChecker350 struct {
	EmptyValueName []string
	EmptyRegexName []string
}
type VersionChecker355 struct {
	EmptyValueName []string
	EmptyRegexName []string
}

接口的实现,定义了两个check方式,方便后续根据不同parse做补充

func (v *VersionChecker336) CheckContainsEmptyValueName(key string) bool {
	if v.EmptyValueName == nil {
		v.EmptyValueName = []string{
			"instantaneous_output_repl_kbps",
			"total_net_output_bytes",
			"cache_db_num",
			"hits_per_sec",
			"cache_status",
			"total_net_input_bytes",
			"instantaneous_output_kbps",
			"instantaneous_input_kbps",
			"total_net_repl_input_bytes",
			"instantaneous_input_repl_kbps",
			"slow_logs_count",
			"total_net_repl_output_bytes",
			"cache_memory",
		}
	}
	for _, str := range v.EmptyValueName {
		if str == key {
			return true
		}
	}
	return false
}
func (v *VersionChecker336) CheckContainsEmptyRegexName(key string) bool {
	if v.EmptyRegexName == nil {
		v.EmptyRegexName = []string{
			"hitratio_per_sec",
		}
	}
	for _, str := range v.EmptyRegexName {
		if str == key {
			return true
		}
	}
	return false
}

只有在opt.CurrentVersion ==nil and 当前字段不在当前版本的check列表才打印日志

		if opt.CurrentVersion == nil || !opt.CurrentVersion.CheckContainsEmptyRegexName(p.name) {
			log.Warnf("regexParser::Parse reg find sub match nil. name:%s", p.name)
		}

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced version checking capabilities in the metrics parsing system.
    • Added a new function to select the appropriate version checker based on the provided version.
  • Enhancements

    • Improved error handling and logging by integrating version-specific checks into the parsing logic.
    • Enhanced the collectInfo method to include version validation and tailored handling for different Pika versions.
  • Bug Fixes

    • Enhanced robustness of the metrics collection process with tailored handling for different Pika versions.

Copy link

coderabbitai bot commented Nov 13, 2024

Walkthrough

The pull request introduces significant enhancements to the metrics/parser.go and pika.go files. Key modifications include the addition of a CurrentVersion field in the ParseOption structure, enabling version-specific checks through the new VersionChecker interface. Three concrete implementations of this interface are introduced, allowing tailored error handling based on the version of Pika being used. The collectInfo method in pika.go is updated to utilize this new version checking capability, improving the robustness of the metrics collection process.

Changes

File Path Change Summary
tools/pika_exporter/exporter/metrics/parser.go - Added CurrentVersion VersionChecker field to ParseOption struct.
- Introduced VersionChecker interface.
- Added types VersionChecker336, VersionChecker350, VersionChecker355 with respective methods for checking empty value and regex names.
- Updated parsing logic to utilize CurrentVersion for conditional logging.
tools/pika_exporter/exporter/pika.go - Added selectversion function to determine the appropriate version checker.
- Updated collectInfo method to include CurrentVersion in parseOpt structure.
- Added constants for version strings and a validation function for version format.

Possibly related PRs

  • fix:macos13 #2937: The changes in this PR do not relate to the modifications in the main PR, as they focus on build and test processes rather than any code-level changes in the metrics/parser.go or related functionality.

Suggested labels

☢️ Bug

Poem

In the land of metrics, where data flows,
A rabbit found versions, as the parser grows.
With checks for the empty, and logs that will shine,
Each version now dances, in perfect design.
So hop with delight, for the changes are here,
A robust little system, let’s give a cheer! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added Invalid PR Title ☢️ Bug Something isn't working labels Nov 13, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
tools/pika_exporter/exporter/pika.go (2)

267-281: Add unit tests for version selection logic

The version selection logic is critical for the metrics collection functionality. Unit tests should be added to ensure correct behavior for various scenarios.

Would you like me to help generate comprehensive unit tests for the selectversion function? The tests would cover:

  • Valid versions (3.3.6, 3.5.0, 3.5.5)
  • Invalid version formats
  • Unsupported versions
  • Edge cases

267-281: Consider a more maintainable version handling architecture

The current switch-based implementation might become unwieldy as more versions are supported. Consider these architectural improvements:

  1. Use a version registry pattern to dynamically register version checkers
  2. Implement version range support instead of exact version matching
  3. Consider using semantic versioning for more flexible version comparison

Example of a registry pattern:

type VersionRegistry struct {
    checkers map[string]metrics.VersionChecker
}

func (r *VersionRegistry) Register(version string, checker metrics.VersionChecker) {
    r.checkers[version] = checker
}

func (r *VersionRegistry) GetChecker(version string) metrics.VersionChecker {
    // Implementation with version range support
}
tools/pika_exporter/exporter/metrics/parser.go (5)

Line range hint 346-353: Handle errors appropriately in convertTimeToUnix

The function convertTimeToUnix returns 0, nil when time.Parse fails. This hides the parsing error from the caller and may lead to incorrect values being used without indication of the failure.

Consider returning the error to the caller to allow proper error handling:

-		return 0, nil
+		return 0, err

Line range hint 328-333: Propagate parsing errors in timeParser.Parse

In timeParser.Parse, the error returned by convertTimeToUnix is currently ignored. This can lead to incorrect metric values being used without awareness of the parsing failure.

Modify the error handling to ensure parsing errors are addressed:

if err != nil {
    log.Warnf("Failed to parse time '%s': %v", v, err)
    return
}
metric.Value = float64(t)

Line range hint 435-437: Handle errors returned by recursive calls in StructToMap

In StructToMap, the error returned by recursive calls is being ignored:

subMap, subCmdMap, _ := StructToMap(value)

Consider handling the error to capture and propagate any issues that may occur during recursion:

subMap, subCmdMap, err := StructToMap(value)
if err != nil {
    return nil, nil, err
}

Line range hint 372-378: Avoid using panic in mustNewVersionConstraint

The function mustNewVersionConstraint uses panic to handle errors from semver.NewConstraint. Relying on panic for error handling can lead to unexpected crashes and is not recommended.

Consider returning the error to the caller so it can be handled appropriately:

func newVersionConstraint(version string) (*semver.Constraints, error) {
    c, err := semver.NewConstraint(version)
    if err != nil {
        return nil, err
    }
    return c, nil
}

Line range hint 299-308: Simplify conditional branching in normalParser.Parse

The else block after the return statement is unnecessary since the function will exit if the condition is met. Removing the else block can make the code cleaner and more readable.

Refactor the code as follows:

if v, ok := findInMap(m.ValueName, opt.Extracts); !ok {
    if opt.CurrentVersion == nil || !opt.CurrentVersion.CheckContainsEmptyValueName(m.ValueName) {
        log.Warnf("normalParser::Parse not found value. metricName:%s valueName:%s", m.Name, m.ValueName)
    }
    return
}
metric.Value = convertToFloat64(v)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4820646 and d681cf6.

📒 Files selected for processing (2)
  • tools/pika_exporter/exporter/metrics/parser.go (4 hunks)
  • tools/pika_exporter/exporter/pika.go (2 hunks)
🔇 Additional comments (6)
tools/pika_exporter/exporter/pika.go (1)

255-258: ⚠️ Potential issue

Consider handling unsupported versions

The CurrentVersion field is initialized with the result of selectversion, which returns nil for unsupported versions. This might lead to nil pointer dereferences in the metrics parsing logic.

Let's verify the version handling in the metrics package:

Consider either:

  1. Setting a default version checker for unsupported versions
  2. Adding explicit nil checks before using CurrentVersion
tools/pika_exporter/exporter/metrics/parser.go (5)

60-72: Avoid data races in lazy initialization of VersionChecker fields

Similarly, the method CheckContainsEmptyRegexName in VersionChecker336 lazily initializes the EmptyRegexName slice, which can lead to data races under concurrent access.


79-95: Avoid data races in lazy initialization of VersionChecker fields

The method CheckContainsEmptyValueName in VersionChecker350 also performs lazy initialization of EmptyValueName, potentially causing data races if accessed concurrently.


96-108: Avoid data races in lazy initialization of VersionChecker fields

The method CheckContainsEmptyRegexName in VersionChecker350 lazily initializes EmptyRegexName, which might lead to data races with concurrent access.


115-130: Avoid data races in lazy initialization of VersionChecker fields

The method CheckContainsEmptyValueName in VersionChecker355 performs lazy initialization of EmptyValueName, which is not thread-safe under concurrent access.


131-147: Avoid data races in lazy initialization of VersionChecker fields

Similarly, CheckContainsEmptyRegexName in VersionChecker355 lazily initializes EmptyRegexName, causing potential data races.

Comment on lines 267 to 281
func selectversion(version string) metrics.VersionChecker {
var v metrics.VersionChecker

switch version {
case "3.3.6":
v = &metrics.VersionChecker336{}
case "3.5.5":
v = &metrics.VersionChecker355{}
case "3.5.0":
v = &metrics.VersionChecker350{}
default:
return nil
}
return v
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve version handling robustness

The current implementation has several areas for improvement:

  1. Hard-coded version strings are error-prone
  2. Limited version support might be too restrictive
  3. No validation of version string format

Consider these improvements:

+// Version constants to avoid typos and improve maintainability
+const (
+    VERSION_336 = "3.3.6"
+    VERSION_350 = "3.5.0"
+    VERSION_355 = "3.5.5"
+)

 func selectversion(version string) metrics.VersionChecker {
-    var v metrics.VersionChecker
+    // Validate version format
+    if !isValidVersion(version) {
+        log.Warnf("Invalid version format: %s", version)
+        return getDefaultVersionChecker()
+    }

     switch version {
-    case "3.3.6":
+    case VERSION_336:
         return &metrics.VersionChecker336{}
-    case "3.5.5":
+    case VERSION_355:
         return &metrics.VersionChecker355{}
-    case "3.5.0":
+    case VERSION_350:
         return &metrics.VersionChecker350{}
     default:
-        return nil
+        // Use the closest supported version
+        return findClosestVersionChecker(version)
     }
-    return v
 }

+// isValidVersion validates the version string format (e.g., x.y.z)
+func isValidVersion(version string) bool {
+    matched, _ := regexp.MatchString(`^\d+\.\d+\.\d+$`, version)
+    return matched
+}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 35 to 59
func (v *VersionChecker336) CheckContainsEmptyValueName(key string) bool {
if v.EmptyValueName == nil {
v.EmptyValueName = []string{
"instantaneous_output_repl_kbps",
"total_net_output_bytes",
"cache_db_num",
"hits_per_sec",
"cache_status",
"total_net_input_bytes",
"instantaneous_output_kbps",
"instantaneous_input_kbps",
"total_net_repl_input_bytes",
"instantaneous_input_repl_kbps",
"slow_logs_count",
"total_net_repl_output_bytes",
"cache_memory",
}
}
for _, str := range v.EmptyValueName {
if str == key {
return true
}
}
return false
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid data races in lazy initialization of VersionChecker fields

The method CheckContainsEmptyValueName in VersionChecker336 performs lazy initialization of the EmptyValueName slice by modifying it during method calls. If instances of VersionChecker336 are accessed concurrently by multiple goroutines, this can lead to data races since the slice is modified without synchronization.

To fix this issue, consider initializing the EmptyValueName slice when creating the VersionChecker336 instance instead of during method calls. This ensures thread safety and avoids potential data races.

@buzhimingyonghu buzhimingyonghu changed the title Fix matching issues between different versions fix: fix matching issues between different versions Nov 13, 2024
@Mixficsol Mixficsol changed the title fix: fix matching issues between different versions fix: matching issues between different versions Nov 13, 2024
@chejinge chejinge changed the title fix: matching issues between different versions feat:matching issues between different versions Nov 13, 2024
@github-actions github-actions bot added the ✏️ Feature New feature or request label Nov 15, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (4)
tools/pika_exporter/exporter/pika.go (1)

267-271: Improve version constants organization and documentation

Consider these improvements for better maintainability:

  1. Add prefix to avoid naming conflicts
  2. Add documentation explaining version significance
 const (
-	VERSION_336 = "3.3.6"
-	VERSION_350 = "3.5.0"
-	VERSION_355 = "3.5.5"
+	// PIKA_VERSION_336 represents the first version with metrics support
+	PIKA_VERSION_336 = "3.3.6"
+	// PIKA_VERSION_350 introduces enhanced metrics collection
+	PIKA_VERSION_350 = "3.5.0"
+	// PIKA_VERSION_355 is the latest supported version with full metrics capability
+	PIKA_VERSION_355 = "3.5.5"
 )
tools/pika_exporter/exporter/metrics/parser.go (3)

20-30: Add interface documentation

The VersionChecker interface and its methods would benefit from documentation explaining:

  • The purpose of the interface
  • The contract for each method
  • Expected behavior when a key is found/not found

Add documentation like this:

+// VersionChecker defines version-specific validation logic for metric names
 type VersionChecker interface {
+    // CheckContainsEmptyValueName returns true if the given key is expected to have
+    // an empty value for this version
     CheckContainsEmptyValueName(key string) bool
+    // CheckContainsEmptyRegexName returns true if the given key is expected to have
+    // empty regex matches for this version
     CheckContainsEmptyRegexName(key string) bool
+    // InitVersionChecker initializes the checker's internal state
     InitVersionChecker()
 }

115-154: Reconsider version numbers in regex names

Including version numbers in regex names (keyspace_info_>=3.1.0, binlog_>=3.2.0, etc.) could make maintenance difficult as new versions are added.

Consider:

  1. Using semantic version parsing to determine feature availability
  2. Creating a version-feature mapping configuration
  3. Implementing a more flexible feature detection mechanism

246-248: Enhance error messages with version context

When logging warnings about missing values or regex matches, include version information to help with debugging.

-    log.Warnf("regexParser::Parse reg find sub match nil. name:%s", p.name)
+    log.Warnf("regexParser::Parse reg find sub match nil. name:%s, version:%v", p.name, opt.Version)

-    log.Warnf("normalParser::Parse not found value. metricName:%s valueName:%s", m.Name, m.ValueName)
+    log.Warnf("normalParser::Parse not found value. metricName:%s valueName:%s, version:%v", m.Name, m.ValueName, opt.Version)

Also applies to: 306-308

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d681cf6 and 67e92bc.

📒 Files selected for processing (2)
  • tools/pika_exporter/exporter/metrics/parser.go (4 hunks)
  • tools/pika_exporter/exporter/pika.go (2 hunks)
🔇 Additional comments (2)
tools/pika_exporter/exporter/pika.go (1)

273-291: Verify version checker usage across codebase

Let's verify that all version checker usage patterns are consistent with these changes.

✅ Verification successful

Let me gather more specific information about the version checker implementations and their usage.


Based on the gathered information, I can now provide the final response:

Version checker implementation is consistent and properly encapsulated

The version checker implementation follows a clean interface pattern where:

  • The interface and implementations are properly defined in metrics/parser.go
  • Each version (3.3.6, 3.5.0, 3.5.5) has its own checker implementation with specific empty value handling
  • Version selection is centralized in selectversion() with proper validation
  • Usage is limited to metrics collection initialization with proper version constraints
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for version checker usage patterns across the codebase

# Find all files that might use version checkers
echo "Files potentially using version checkers:"
rg -l "VersionChecker|CurrentVersion" --type go

# Check for potential version string usage
echo -e "\nPotential version string usage:"
rg "3\.[0-9]+\.[0-9]+" --type go

# Look for other version-related functions
echo -e "\nOther version-related functions:"
ast-grep --pattern 'func $name($params) {
  $$$
  version
  $$$
}'

Length of output: 8110


Script:

#!/bin/bash
# Check version checker implementations and usage
echo "Version checker implementations:"
rg -A 5 "type VersionChecker" tools/pika_exporter/exporter/metrics/

echo -e "\nVersion checker initialization and usage:"
rg -A 5 "InitVersionChecker|selectversion" --type go

echo -e "\nVersion constants and validation:"
rg "VERSION_|isValidVersion" tools/pika_exporter/exporter/pika.go

Length of output: 5288

tools/pika_exporter/exporter/metrics/parser.go (1)

77-113: Apply the same optimizations as VersionChecker336

The implementation has the same optimization opportunities as discussed for VersionChecker336.

Comment on lines +293 to +297
// isValidVersion validates the version string format (e.g., x.y.z)
func isValidVersion(version string) bool {
matched, _ := regexp.MatchString(`^\d+\.\d+\.\d+$`, version)
return matched
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize version validation with pre-compiled regex

The current implementation compiles the regex on every call and ignores potential compilation errors. Consider pre-compiling the regex for better performance and error handling.

+var versionRegex = regexp.MustCompile(`^\d+\.\d+\.\d+$`)
+
 // isValidVersion validates the version string format (e.g., x.y.z)
 func isValidVersion(version string) bool {
-	matched, _ := regexp.MatchString(`^\d+\.\d+\.\d+$`, version)
-	return matched
+	return versionRegex.MatchString(version)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// isValidVersion validates the version string format (e.g., x.y.z)
func isValidVersion(version string) bool {
matched, _ := regexp.MatchString(`^\d+\.\d+\.\d+$`, version)
return matched
}
var versionRegex = regexp.MustCompile(`^\d+\.\d+\.\d+$`)
// isValidVersion validates the version string format (e.g., x.y.z)
func isValidVersion(version string) bool {
return versionRegex.MatchString(version)
}

Comment on lines +255 to +258
Version: version,
Extracts: extracts,
Info: info,
CurrentVersion: selectversion(version.Original()),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for unsupported versions

The CurrentVersion field might be nil if selectversion returns nil for unsupported versions. This could lead to nil pointer dereferences in the metrics parsing logic.

Consider adding error handling:

-		CurrentVersion: selectversion(version.Original()),
+		CurrentVersion: selectversion(version.Original())
+	}
+	if parseOpt.CurrentVersion == nil {
+		return fmt.Errorf("unsupported Pika version: %s", version.Original())

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +273 to +291
func selectversion(version string) metrics.VersionChecker {
if !isValidVersion(version) {
log.Warnf("Invalid version format: %s", version)
return nil
}
var v metrics.VersionChecker
switch version {
case VERSION_336:
v = &metrics.VersionChecker336{}
case VERSION_355:
v = &metrics.VersionChecker355{}
case VERSION_350:
v = &metrics.VersionChecker350{}
default:
return nil
}
v.InitVersionChecker()
return v
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve version selection logic and error handling

The function can be improved for better error handling and cleaner code:

  1. Return error to explain why version is unsupported
  2. Simplify the code by removing unnecessary variable
  3. Use the renamed constants
-func selectversion(version string) metrics.VersionChecker {
+func selectversion(version string) (metrics.VersionChecker, error) {
 	if !isValidVersion(version) {
 		log.Warnf("Invalid version format: %s", version)
-		return nil
+		return nil, fmt.Errorf("invalid version format: %s", version)
 	}
-	var v metrics.VersionChecker
 	switch version {
-	case VERSION_336:
-		v = &metrics.VersionChecker336{}
-	case VERSION_355:
-		v = &metrics.VersionChecker355{}
-	case VERSION_350:
-		v = &metrics.VersionChecker350{}
+	case PIKA_VERSION_336:
+		checker := &metrics.VersionChecker336{}
+		checker.InitVersionChecker()
+		return checker, nil
+	case PIKA_VERSION_355:
+		checker := &metrics.VersionChecker355{}
+		checker.InitVersionChecker()
+		return checker, nil
+	case PIKA_VERSION_350:
+		checker := &metrics.VersionChecker350{}
+		checker.InitVersionChecker()
+		return checker, nil
 	default:
-		return nil
+		return nil, fmt.Errorf("unsupported version: %s", version)
 	}
-	v.InitVersionChecker()
-	return v
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +31 to +75
type VersionChecker336 struct {
EmptyValueName []string
EmptyRegexName []string
}

func (v *VersionChecker336) InitVersionChecker() {
if v.EmptyValueName == nil {
v.EmptyValueName = []string{
"instantaneous_output_repl_kbps",
"total_net_output_bytes",
"cache_db_num",
"hits_per_sec",
"cache_status",
"total_net_input_bytes",
"instantaneous_output_kbps",
"instantaneous_input_kbps",
"total_net_repl_input_bytes",
"instantaneous_input_repl_kbps",
"slow_logs_count",
"total_net_repl_output_bytes",
"cache_memory",
}
}
if v.EmptyRegexName == nil {
v.EmptyRegexName = []string{
"hitratio_per_sec",
}
}
}
func (v *VersionChecker336) CheckContainsEmptyValueName(key string) bool {
for _, str := range v.EmptyValueName {
if str == key {
return true
}
}
return false
}
func (v *VersionChecker336) CheckContainsEmptyRegexName(key string) bool {
for _, str := range v.EmptyRegexName {
if str == key {
return true
}
}
return false
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize version checker implementation

The current implementation has several areas for improvement:

  1. Thread safety issues during lazy initialization (as noted in past review)
  2. Linear search performance could be improved using maps
  3. Duplicate code pattern across version checkers

Consider these improvements:

 type VersionChecker336 struct {
-    EmptyValueName []string
-    EmptyRegexName []string
+    EmptyValueName map[string]struct{}
+    EmptyRegexName map[string]struct{}
 }

 func (v *VersionChecker336) InitVersionChecker() {
-    if v.EmptyValueName == nil {
-        v.EmptyValueName = []string{
+    v.EmptyValueName = map[string]struct{}{
-            "instantaneous_output_repl_kbps",
+            "instantaneous_output_repl_kbps": {},
         // ... other values ...
     }
-    }
-    if v.EmptyRegexName == nil {
-        v.EmptyRegexName = []string{
+    v.EmptyRegexName = map[string]struct{}{
-            "hitratio_per_sec",
+            "hitratio_per_sec": {},
         }
-    }
 }

 func (v *VersionChecker336) CheckContainsEmptyValueName(key string) bool {
-    for _, str := range v.EmptyValueName {
-        if str == key {
-            return true
-        }
-    }
-    return false
+    _, ok := v.EmptyValueName[key]
+    return ok
 }

This refactoring:

  1. Eliminates thread-safety issues by removing lazy initialization
  2. Improves lookup performance from O(n) to O(1) using maps
  3. Could be extracted into a base struct to reduce code duplication

Committable suggestion skipped: line range outside the PR's diff.

@cheniujh cheniujh changed the title feat:matching issues between different versions fix: pika export error output due to versions dismatch Nov 18, 2024
@cheniujh cheniujh changed the title fix: pika export error output due to versions dismatch fix: pika exporter error output due to versions dismatch Nov 18, 2024
@Mixficsol Mixficsol merged commit 77177c7 into OpenAtomFoundation:unstable Nov 18, 2024
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
☢️ Bug Something isn't working ✏️ Feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants