Merged in feature/log-version (pull request #185)

inject and print version at startup for all services

* inject and print version

* coverage
This commit is contained in:
Jay Brown
2025-09-18 21:06:21 +00:00
parent 8a13b6d3b1
commit a6e081e5cd
17 changed files with 233 additions and 5 deletions
+2 -1
View File
@@ -33,13 +33,14 @@ ENV CC=musl-gcc
ARG GIT_VERSION=dev
ARG GIT_COMMIT=unknown
ARG BUILD_TIME=unknown
RUN go build \
-mod vendor \
-tags musl \
-trimpath \
-installsuffix cgo \
-ldflags "-s -w -linkmode external -extldflags '-static -Wl,--as-needed -Wl,--gc-sections -Wl,-O1' -X main.version=${GIT_VERSION} -X main.gitCommit=${GIT_COMMIT}" \
-ldflags "-s -w -linkmode external -extldflags '-static -Wl,--as-needed -Wl,--gc-sections -Wl,-O1' -X queryorchestration/internal/serviceconfig/build.version=${GIT_VERSION} -X queryorchestration/internal/serviceconfig/build.gitCommit=${GIT_COMMIT} -X queryorchestration/internal/serviceconfig/build.buildTime=${BUILD_TIME}" \
-o bin/ ./cmd/...
FROM scratch AS final
+4
View File
@@ -13,6 +13,7 @@ import (
clientsyncrunner "queryorchestration/api/clientSyncRunner"
clientsync "queryorchestration/internal/client/sync"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
"queryorchestration/internal/serviceconfig/queue/documentsync"
_ "github.com/lib/pq"
@@ -24,6 +25,9 @@ type ClientSyncConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("clientSyncRunner")
ctx := context.Background()
cfg := &ClientSyncConfig{}
+4
View File
@@ -15,6 +15,7 @@ import (
doccleanrunner "queryorchestration/api/docCleanRunner"
documentclean "queryorchestration/internal/document/clean"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
"queryorchestration/internal/serviceconfig/objectstore"
"queryorchestration/internal/serviceconfig/queue/documenttext"
@@ -28,6 +29,9 @@ type DocCleanConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("docCleanRunner")
ctx := context.Background()
cfg := &DocCleanConfig{}
+4
View File
@@ -23,6 +23,7 @@ import (
docinitrunner "queryorchestration/api/docInitRunner"
documentinit "queryorchestration/internal/document/init"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
documentsyncc "queryorchestration/internal/serviceconfig/queue/documentsync"
_ "github.com/lib/pq"
@@ -34,6 +35,9 @@ type DocInitConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("docInitRunner")
ctx := context.Background()
cfg := &DocInitConfig{}
+4
View File
@@ -19,6 +19,7 @@ import (
"queryorchestration/internal/document"
documentsync "queryorchestration/internal/document/sync"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
documentcleanc "queryorchestration/internal/serviceconfig/queue/documentclean"
_ "github.com/lib/pq"
@@ -30,6 +31,9 @@ type DocSyncConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("docSyncRunner")
ctx := context.Background()
cfg := &DocSyncConfig{}
+4
View File
@@ -15,6 +15,7 @@ import (
doctextrunner "queryorchestration/api/docTextRunner"
documenttext "queryorchestration/internal/document/text"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
"queryorchestration/internal/serviceconfig/objectstore"
"queryorchestration/internal/serviceconfig/queue/querysync"
"queryorchestration/internal/serviceconfig/textract"
@@ -30,6 +31,9 @@ type DocTextConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("docTextRunner")
ctx := context.Background()
cfg := &DocTextConfig{}
+5
View File
@@ -5,9 +5,14 @@ import (
"errors"
"net/http"
"os"
"queryorchestration/internal/serviceconfig/build"
)
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("healthcheck")
err := check()
if err != nil {
os.Exit(1)
+4
View File
@@ -29,6 +29,7 @@ import (
"queryorchestration/internal/query/result"
"queryorchestration/internal/server/api"
"queryorchestration/internal/serviceconfig"
"queryorchestration/internal/serviceconfig/build"
"queryorchestration/internal/serviceconfig/objectstore"
"queryorchestration/internal/serviceconfig/queue/clientsync"
"queryorchestration/internal/serviceconfig/queue/queryversionsync"
@@ -57,6 +58,9 @@ type QueryAPIConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("queryAPI")
ctx := context.Background()
cfg := &QueryAPIConfig{}
+4
View File
@@ -18,6 +18,7 @@ import (
resultset "queryorchestration/internal/query/result/set"
resultsync "queryorchestration/internal/query/result/sync"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
queryc "queryorchestration/internal/serviceconfig/queue/query"
_ "github.com/lib/pq"
@@ -29,6 +30,9 @@ type QueryConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("queryRunner")
ctx := context.Background()
cfg := &QueryConfig{}
+4
View File
@@ -24,6 +24,7 @@ import (
resultsync "queryorchestration/internal/query/result/sync"
querysync "queryorchestration/internal/query/sync"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
queryc "queryorchestration/internal/serviceconfig/queue/query"
_ "github.com/lib/pq"
@@ -35,6 +36,9 @@ type QuerySyncConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("querySyncRunner")
ctx := context.Background()
cfg := &QuerySyncConfig{}
+4
View File
@@ -13,6 +13,7 @@ import (
queryversionsyncrunner "queryorchestration/api/queryVersionSyncRunner"
queryversionsync "queryorchestration/internal/query/versionsync"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
"queryorchestration/internal/serviceconfig/queue/clientsync"
_ "github.com/lib/pq"
@@ -24,6 +25,9 @@ type QueryVersionSyncConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("queryVersionSyncRunner")
ctx := context.Background()
cfg := &QueryVersionSyncConfig{}
+4
View File
@@ -15,6 +15,7 @@ import (
storeeventrunner "queryorchestration/api/storeEventRunner"
documentstore "queryorchestration/internal/document/store"
"queryorchestration/internal/server/runner"
"queryorchestration/internal/serviceconfig/build"
"queryorchestration/internal/serviceconfig/queue/documentinit"
_ "github.com/lib/pq"
@@ -26,6 +27,9 @@ type StoreEventConfig struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("storeEventRunner")
ctx := context.Background()
cfg := &StoreEventConfig{}
+4
View File
@@ -11,6 +11,7 @@ import (
"queryorchestration/internal/serviceconfig"
"queryorchestration/internal/serviceconfig/aws"
"queryorchestration/internal/serviceconfig/build"
"queryorchestration/internal/serviceconfig/objectstore"
"queryorchestration/internal/serviceconfig/queue/querysync"
"queryorchestration/internal/serviceconfig/textract"
@@ -27,6 +28,9 @@ type Config struct {
}
func main() {
// Print version information before any environment checks
build.PrintVersionInfo("textExtractor")
ctx := context.Background()
directory := "files/"
+4 -1
View File
@@ -45,7 +45,10 @@ func New(ctx context.Context, cfg Config) (func() error, error) {
version := build.GetVersion()
if cfg.GetLogger() != nil {
cfg.GetLogger().Info("Starting", "version", version)
cfg.GetLogger().Info("Starting",
"version", version,
"buildTime", build.GetBuildTime(),
"commit", build.GetGitCommit())
}
err := database.RunMigrations(ctx, cfg)
+46 -2
View File
@@ -2,6 +2,7 @@ package build
import (
"fmt"
"os"
"runtime/debug"
"sync"
"time"
@@ -11,6 +12,13 @@ const (
SystemName = "doczy"
)
// These variables will be set via ldflags during build
var (
version = "(devel)"
gitCommit = "unknown"
buildTime = "unknown"
)
func IsValidUnixVersion(v int64) error {
currentVersion := GetVersionUnixTimestamp()
@@ -60,8 +68,9 @@ func GetVersionUnixTimestamp() int64 {
return GetVersionTimestamp().UnixMilli()
}
// 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.
// GetVersion returns the version of the application.
// It first checks if a version was set via ldflags during build.
// If not set via ldflags, it falls back to the Golang build info format.
// 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.
@@ -72,9 +81,44 @@ func GetVersionUnixTimestamp() int64 {
//
// An example of a version v0.0.2-0.20250310175756-a91372dc0602+dirty.
func GetVersion() string {
// Check if version was set via ldflags
if version != "" && version != "(devel)" {
return version
}
// Fall back to debug.ReadBuildInfo
info, ok := debug.ReadBuildInfo()
if !ok {
return "unknown"
}
return info.Main.Version
}
// GetGitCommit returns the git commit hash set during build.
// Returns "unknown" if not set via ldflags.
func GetGitCommit() string {
return gitCommit
}
// GetBuildTime returns the build time set during build.
// Returns "unknown" if not set via ldflags.
func GetBuildTime() string {
return buildTime
}
// PrintVersionInfo prints version information to stderr.
// This should be called at the very beginning of main() before any environment checks.
// It prints to stderr to ensure output even if stdout is redirected or logging isn't initialized.
// Format: Starting <service> version=<version> buildTime=<buildTime> commit=<commit>
func PrintVersionInfo(serviceName string) {
// If version already contains timestamp and commit (format: YYYYMMDD.HHMMSS-commit),
// just use that. Otherwise, construct from parts.
if version != "(devel)" && version != "" {
fmt.Fprintf(os.Stderr, "Starting %s version=%s buildTime=%s commit=%s\n",
serviceName, version, buildTime, gitCommit)
} else {
// Fallback format when not built via Docker
fmt.Fprintf(os.Stderr, "Starting %s version=%s commit=%s\n",
serviceName, GetVersion(), GetGitCommit())
}
}
+125
View File
@@ -1,7 +1,10 @@
package build
import (
"bytes"
"os"
"runtime/debug"
"strings"
"testing"
"time"
@@ -129,3 +132,125 @@ func TestGetVersion(t *testing.T) {
t.Errorf("Version not consistent between calls: '%s' != '%s'", version, version2)
}
}
func TestGetGitCommit(t *testing.T) {
// Test that GetGitCommit returns a non-empty string
commit := GetGitCommit()
if commit == "" {
t.Error("Git commit should not be empty")
}
// In test environment, it should return the default value
if commit != "unknown" && commit != gitCommit {
t.Errorf("Unexpected commit value: %s", commit)
}
}
func TestGetBuildTime(t *testing.T) {
// Test that GetBuildTime returns a non-empty string
bt := GetBuildTime()
if bt == "" {
t.Error("Build time should not be empty")
}
// In test environment, it should return the default value
if bt != "unknown" && bt != buildTime {
t.Errorf("Unexpected build time value: %s", bt)
}
}
func TestPrintVersionInfo(t *testing.T) {
// Save original stderr
oldStderr := os.Stderr
defer func() { os.Stderr = oldStderr }()
// Create a pipe to capture stderr
r, w, _ := os.Pipe()
os.Stderr = w
// Test 1: PrintVersionInfo with default values (devel)
t.Run("with devel version", func(t *testing.T) {
// Save original values
originalVersion := version
originalCommit := gitCommit
originalBuildTime := buildTime
// Set test values
version = "(devel)"
gitCommit = "testcommit"
buildTime = "testtime"
// Call PrintVersionInfo
PrintVersionInfo("testService")
// Close writer and read output
w.Close()
var buf bytes.Buffer
_, err := buf.ReadFrom(r)
if err != nil {
t.Fatalf("Failed to read from pipe: %v", err)
}
output := buf.String()
// Check output contains expected parts
if !strings.Contains(output, "Starting testService") {
t.Errorf("Output should contain service name, got: %s", output)
}
if !strings.Contains(output, "version=") {
t.Errorf("Output should contain version, got: %s", output)
}
// Restore original values
version = originalVersion
gitCommit = originalCommit
buildTime = originalBuildTime
})
// Create new pipe for second test
r2, w2, _ := os.Pipe()
os.Stderr = w2
// Test 2: PrintVersionInfo with custom values
t.Run("with custom version", func(t *testing.T) {
// Save original values
originalVersion := version
originalCommit := gitCommit
originalBuildTime := buildTime
// Set test values
version = "20231201.123456-abc123"
gitCommit = "abc123def456"
buildTime = "2023-12-01T12:34:56Z"
// Call PrintVersionInfo
PrintVersionInfo("customService")
// Close writer and read output
w2.Close()
var buf bytes.Buffer
_, err := buf.ReadFrom(r2)
if err != nil {
t.Fatalf("Failed to read from pipe: %v", err)
}
output := buf.String()
// Check output contains all expected parts
if !strings.Contains(output, "Starting customService") {
t.Errorf("Output should contain service name, got: %s", output)
}
if !strings.Contains(output, "version=20231201.123456-abc123") {
t.Errorf("Output should contain version, got: %s", output)
}
if !strings.Contains(output, "buildTime=2023-12-01T12:34:56Z") {
t.Errorf("Output should contain build time, got: %s", output)
}
if !strings.Contains(output, "commit=abc123def456") {
t.Errorf("Output should contain commit, got: %s", output)
}
// Restore original values
version = originalVersion
gitCommit = originalCommit
buildTime = originalBuildTime
})
}
+7 -1
View File
@@ -5,8 +5,12 @@ version: "3"
vars:
DOCKERFILE: "build/Dockerfile"
BUILD_TIME:
sh: date -u +"%Y-%m-%dT%H:%M:%SZ"
GIT_SHORT_COMMIT:
sh: git rev-parse --short HEAD
GIT_VERSION:
sh: git describe --tags --always
sh: echo "$(date -u +"%Y%m%d.%H%M%S")-$(git rev-parse --short HEAD)"
GIT_COMMIT:
sh: git rev-parse HEAD
@@ -21,6 +25,7 @@ tasks:
docker build \
--build-arg "GIT_VERSION={{.GIT_VERSION}}" \
--build-arg "GIT_COMMIT={{.GIT_COMMIT}}" \
--build-arg "BUILD_TIME={{.BUILD_TIME}}" \
--build-arg BUILDKIT_INLINE_CACHE=1 \
-t {{.IMAGE_NAME}}:latest \
-t {{.IMAGE_NAME}}:{{.GIT_VERSION}} \
@@ -32,5 +37,6 @@ tasks:
docker build \
--build-arg "GIT_VERSION={{.GIT_VERSION}}" \
--build-arg "GIT_COMMIT={{.GIT_COMMIT}}" \
--build-arg "BUILD_TIME={{.BUILD_TIME}}" \
-t {{.IMAGE_NAME}}:debug \
-f build/Dockerfile.debug .