Documentation
¶
Overview ¶
Package info provides a thread-safe, caching implementation for monitor information.
The package offers a flexible way to manage monitor metadata with support for dynamic name and info retrieval through registered functions. It implements both encoding.TextMarshaler and json.Marshaler interfaces for easy serialization.
Key Features ¶
- Thread-safe concurrent access using sync.RWMutex and sync.Map
- Lazy evaluation and caching of dynamic data
- Support for custom name and info retrieval functions
- Built-in text and JSON marshaling
- Efficient cache invalidation on re-registration
Basic Usage ¶
Creating a simple info instance:
info, err := info.New("my-service")
if err != nil {
log.Fatal(err)
}
fmt.Println(info.Name()) // Output: my-service
Dynamic Name ¶
Register a function to provide dynamic names:
info.RegisterName(func() (string, error) {
hostname, err := os.Hostname()
if err != nil {
return "", err
}
return fmt.Sprintf("service-%s", hostname), nil
})
name := info.Name() // Returns "service-<hostname>"
Dynamic Info ¶
Register a function to provide dynamic metadata:
info.RegisterInfo(func() (map[string]interface{}, error) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
return map[string]interface{}{
"version": "1.0.0",
"goroutines": runtime.NumGoroutine(),
"alloc_mb": m.Alloc / 1024 / 1024,
}, nil
})
data := info.Info() // Returns current runtime info
Serialization ¶
The Info type implements standard Go marshaling interfaces:
// Text marshaling
text, err := info.MarshalText()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(text)) // Output: my-service (version: 1.0.0, ...)
// JSON marshaling
jsonData, err := json.Marshal(info)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(jsonData)) // Output: {"Name":"my-service","Info":{...}}
Caching Behavior ¶
Functions are called only once and results are cached:
callCount := 0
info.RegisterName(func() (string, error) {
callCount++
return fmt.Sprintf("name-%d", callCount), nil
})
name1 := info.Name() // callCount = 1, returns "name-1"
name2 := info.Name() // callCount = 1, returns "name-1" (cached)
Re-registration invalidates the cache:
info.RegisterName(func() (string, error) {
return "new-name", nil
})
name3 := info.Name() // Cache cleared, returns "new-name"
Error Handling ¶
If a registered function returns an error, the default name or nil is returned:
info.RegisterName(func() (string, error) {
return "", errors.New("failed to get name")
})
name := info.Name() // Returns default name (not the error value)
Thread Safety ¶
All methods are thread-safe and can be called concurrently:
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
_ = info.Name()
_ = info.Info()
}()
}
wg.Wait()
Performance ¶
The implementation is optimized for read-heavy workloads:
- Cached name reads: ~4 ns/op with 0 allocations
- Cached info reads: ~140 ns/op with 2 allocations
- Name registration: ~37 ns/op with 0 allocations
- Info registration: ~32 ns/op with 0 allocations
Integration ¶
The package integrates seamlessly with the golib monitor system. See github.com/nabbar/golib/monitor for complete monitor functionality.
Example (Caching) ¶
Example_caching demonstrates the caching behavior.
package main
import (
"fmt"
"github.com/nabbar/golib/monitor/info"
)
func main() {
i, _ := info.New("service")
callCount := 0
i.RegisterName(func() (string, error) {
callCount++
return fmt.Sprintf("name-%d", callCount), nil
})
// First call executes the function
name1 := i.Name()
fmt.Printf("First call: %s (callCount: %d)\n", name1, callCount)
// Second call uses cached value
name2 := i.Name()
fmt.Printf("Second call: %s (callCount: %d)\n", name2, callCount)
}
Output: First call: name-1 (callCount: 1) Second call: name-1 (callCount: 1)
Example (ErrorHandling) ¶
Example_errorHandling demonstrates error handling.
package main
import (
"fmt"
"github.com/nabbar/golib/monitor/info"
)
func main() {
i, _ := info.New("default-service")
i.RegisterName(func() (string, error) {
return "", fmt.Errorf("simulated error")
})
// Returns default name on error
name := i.Name()
fmt.Println(name)
}
Output: default-service
Example (MultipleInfo) ¶
Example_multipleInfo demonstrates handling multiple info registrations.
package main
import (
"fmt"
"github.com/nabbar/golib/monitor/info"
)
func main() {
i, _ := info.New("service")
// First registration
i.RegisterInfo(func() (map[string]interface{}, error) {
return map[string]interface{}{
"version": "1.0.0",
}, nil
})
fmt.Println("Version:", i.Info()["version"])
// Re-registration clears cache
i.RegisterInfo(func() (map[string]interface{}, error) {
return map[string]interface{}{
"version": "2.0.0",
}, nil
})
fmt.Println("Version:", i.Info()["version"])
}
Output: Version: 1.0.0 Version: 2.0.0
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Encode ¶
type Encode interface {
// String returns the string representation of the encoding model.
// It concatenates all the key-value pairs of the Info map, separated by commas.
// The key is separated from the value by a colon.
String() string
// Bytes returns the byte representation of the encoding model.
// It is a JSON marshalled version of the encoding model.
//
Bytes() []byte
}
type FuncInfo ¶
FuncInfo is a function type that returns dynamic info data and an optional error. The function is called once and the results are cached unless an error occurs.
type FuncName ¶
FuncName is a function type that returns a dynamic name and an optional error. The function is called once and the result is cached unless an error occurs.
type Info ¶
type Info interface {
montps.Info
// RegisterName registers a function that returns a default name.
// The function must return a string and an error.
// If the function returns an error, the default name is not registered.
//
RegisterName(fct FuncName)
// RegisterInfo registers a function that returns a default info.
// The function must return a map of string to interface{} and an error.
// If the function returns an error, the default info is not registered.
RegisterInfo(fct FuncInfo)
}
func New ¶
New creates a new Info instance with the given default name. The default name is used when no dynamic name function is registered or when it fails. Returns an error if the default name is empty.
Example:
info, err := info.New("my-service")
if err != nil {
log.Fatal(err)
}
fmt.Println(info.Name()) // Output: my-service
Example ¶
ExampleNew demonstrates creating a new Info instance.
package main
import (
"fmt"
"log"
"github.com/nabbar/golib/monitor/info"
)
func main() {
i, err := info.New("my-service")
if err != nil {
log.Fatal(err)
}
fmt.Println(i.Name())
}
Output: my-service