Merged in feature/versionTimestamps (pull request #98)
add GetVersionTimestamp * add GetVersionTimestamp * docs
This commit is contained in:
@@ -20,10 +20,11 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/debug"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"queryorchestration/internal/serviceconfig/observability"
|
||||
|
||||
"queryorchestration/internal/serviceconfig/observability/prometheus"
|
||||
)
|
||||
|
||||
@@ -53,12 +54,10 @@ func getMetricsConfig() prometheus.MetricsConfig {
|
||||
}
|
||||
|
||||
func main() {
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
fmt.Println("Failed to read build info")
|
||||
return
|
||||
}
|
||||
fmt.Printf("Version: %s\n", info.Main.Version)
|
||||
rawVersion := observability.GetVersion()
|
||||
fmt.Printf("Version: %s\n", rawVersion)
|
||||
timeVersion := observability.GetVersionTimestamp()
|
||||
fmt.Printf("Version Timestamp: %s\n", timeVersion.String())
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
@@ -3,6 +3,8 @@ package observability
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"runtime/debug"
|
||||
|
||||
@@ -17,6 +19,48 @@ const (
|
||||
SystemName = "doczy"
|
||||
)
|
||||
|
||||
var startupTime time.Time
|
||||
var startupTimeOnce sync.Once
|
||||
|
||||
func GetVersionTimestamp() time.Time {
|
||||
startupTimeOnce.Do(func() {
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
startupTime = time.Now()
|
||||
return
|
||||
}
|
||||
|
||||
// Look for vcs.time in build settings
|
||||
for _, setting := range info.Settings {
|
||||
if setting.Key == "vcs.time" {
|
||||
// Parse the build timestamp
|
||||
buildTime, err := time.Parse(time.RFC3339, setting.Value)
|
||||
if err == nil {
|
||||
startupTime = buildTime
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Return current time if no build time found
|
||||
startupTime = time.Now()
|
||||
})
|
||||
|
||||
return startupTime
|
||||
}
|
||||
|
||||
// GetVersion returns the version of the application in the Golang build info format.
|
||||
// This is a raw format and will change depending on the build environment and the git tags.
|
||||
// When building from a commit with an associated Git tag (e.g., v1.2.3),
|
||||
//
|
||||
// the runtime version uses the tag name without a timestamp.
|
||||
//
|
||||
// The "+dirty" suffix is appended when there are uncommitted changes
|
||||
//
|
||||
// present in the version control system (VCS) at the time of building.
|
||||
//
|
||||
// An example of a version v0.0.2-0.20250310175756-a91372dc0602+dirty.
|
||||
func GetVersion() string {
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"queryorchestration/internal/serviceconfig/observability"
|
||||
|
||||
@@ -32,3 +33,52 @@ func TestSetOtel(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func TestGetVersionTimestamp(t *testing.T) {
|
||||
// Test 1: First call should set the timestamp
|
||||
t1 := observability.GetVersionTimestamp()
|
||||
if t1.IsZero() {
|
||||
t.Error("GetVersionTimestamp returned zero time")
|
||||
}
|
||||
|
||||
// Test 2: Second call should return exactly the same time
|
||||
time.Sleep(time.Millisecond * 100) // Small delay to ensure time would be different if not cached
|
||||
t2 := observability.GetVersionTimestamp()
|
||||
if !t1.Equal(t2) {
|
||||
t.Errorf("Timestamps should be identical but got t1=%v, t2=%v", t1, t2)
|
||||
}
|
||||
|
||||
// Test 3: Even after a longer delay, should still return the same time
|
||||
time.Sleep(time.Second) // Longer delay
|
||||
t3 := observability.GetVersionTimestamp()
|
||||
if !t1.Equal(t3) {
|
||||
t.Errorf("Timestamp changed after delay: original=%v, new=%v", t1, t3)
|
||||
}
|
||||
|
||||
// Test 4: Returned time should not be in the future
|
||||
if t1.After(time.Now()) {
|
||||
t.Errorf("Timestamp is in the future: %v", t1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetVersion(t *testing.T) {
|
||||
// Test 1: Basic call
|
||||
version := observability.GetVersion()
|
||||
if version == "" {
|
||||
t.Error("Version should not be empty")
|
||||
}
|
||||
|
||||
// Test 2: Should either be "unknown" or follow semver-like pattern
|
||||
if version != "unknown" {
|
||||
// This is a loose check - you might want to make it more strict
|
||||
if len(version) < 3 {
|
||||
t.Errorf("Version '%s' seems too short to be valid", version)
|
||||
}
|
||||
}
|
||||
|
||||
// Test 3: Multiple calls should be consistent
|
||||
version2 := observability.GetVersion()
|
||||
if version != version2 {
|
||||
t.Errorf("Version not consistent between calls: '%s' != '%s'", version, version2)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user