Go Metrics Collection System
This challenge asks you to implement a basic metrics collection system in Go. Such a system is crucial for monitoring application performance, identifying bottlenecks, and ensuring overall system health. You'll be building a system that can record counters and gauges, and expose them in a simple format.
Problem Description
You are tasked with creating a Metrics struct in Go that can track two types of metrics: counters and gauges.
- Counters: Represent cumulative values that only increase over time (e.g., number of requests served, errors encountered).
- Gauges: Represent values that can fluctuate over time (e.g., memory usage, active connections).
The Metrics struct should provide methods to:
- Increment Counter: A method to increment a counter by a given amount.
- Set Gauge: A method to set the value of a gauge.
- Get Counter Value: A method to retrieve the current value of a counter.
- Get Gauge Value: A method to retrieve the current value of a gauge.
- Export Metrics: A method to return a map representing the collected metrics. The map should have string keys (metric names) and values that are either integers (for counters) or floats (for gauges).
The system should handle cases where a metric doesn't exist. If a counter or gauge is accessed before being initialized, return 0 for counters and 0.0 for gauges.
Examples
Example 1:
Input:
Metrics: Initialized with counter "requests" and gauge "memory_usage"
Increment Counter "requests" by 5
Set Gauge "memory_usage" to 1024.0
Get Counter Value "requests"
Get Gauge Value "memory_usage"
Export Metrics
Output:
Counter "requests" value: 5
Gauge "memory_usage" value: 1024.0
Metrics Map: map[memory_usage:1024, requests:5]
Explanation: The counter "requests" is incremented by 5, the gauge "memory_usage" is set to 1024.0, and the final state is exported.
Example 2:
Input:
Metrics: Initialized with counter "errors"
Increment Counter "errors" by 2
Get Counter Value "errors"
Get Gauge Value "nonexistent_gauge"
Export Metrics
Output:
Counter "errors" value: 2
Gauge "nonexistent_gauge" value: 0.0
Metrics Map: map[errors:2]
Explanation: The counter "errors" is incremented by 2. Attempting to get a non-existent gauge returns 0.0.
Example 3: (Edge Case - Metric Not Initialized)
Input:
Metrics: Initialized with no metrics
Get Counter Value "unknown_counter"
Get Gauge Value "unknown_gauge"
Export Metrics
Output:
Counter "unknown_counter" value: 0
Gauge "unknown_gauge" value: 0.0
Metrics Map: map[]
Explanation: Accessing a counter or gauge that hasn't been initialized returns 0 or 0.0 respectively.
Constraints
- Metric names (keys in the map) must be strings.
- Counter values must be integers.
- Gauge values must be floats.
- The
Export Metricsmethod should return a copy of the metrics map to prevent external modification. - The system should be thread-safe. (Consider using
sync.Mutexto protect access to the internal data structures.)
Notes
- Consider using a
mapto store the metrics internally. You could use one map for counters and another for gauges, or a single map with a union type. - Think about how to handle potential race conditions when multiple goroutines access the metrics concurrently.
- The focus is on the core functionality of collecting and exporting metrics. Error handling and more sophisticated features (e.g., aggregations, histograms) are not required for this challenge.
- Start with a basic implementation and then add thread safety. Testing for thread safety can be more complex.
- The
Export Metricsmethod should return a copy of the map to prevent external modification of the internal state. Usemake()to create a new map and copy the values.