{"id":50914308,"url":"https://github.com/phcp-tech/common-library-golang","last_synced_at":"2026-06-16T13:03:44.178Z","repository":{"id":362373040,"uuid":"1257739704","full_name":"phcp-tech/common-library-golang","owner":"phcp-tech","description":"Common library golang for PHCP ecosystem.","archived":false,"fork":false,"pushed_at":"2026-06-11T06:11:07.000Z","size":232,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-11T07:20:04.706Z","etag":null,"topics":["component","env","go","microservice","ringbuf","rotate-logs"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phcp-tech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-03T01:03:17.000Z","updated_at":"2026-06-11T06:11:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/phcp-tech/common-library-golang","commit_stats":null,"previous_names":["phcp-tech/common-library-golang"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/phcp-tech/common-library-golang","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phcp-tech%2Fcommon-library-golang","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phcp-tech%2Fcommon-library-golang/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phcp-tech%2Fcommon-library-golang/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phcp-tech%2Fcommon-library-golang/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phcp-tech","download_url":"https://codeload.github.com/phcp-tech/common-library-golang/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phcp-tech%2Fcommon-library-golang/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34406824,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["component","env","go","microservice","ringbuf","rotate-logs"],"created_at":"2026-06-16T13:03:42.942Z","updated_at":"2026-06-16T13:03:44.170Z","avatar_url":"https://github.com/phcp-tech.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHCP: common-library-golang\r\n\r\n[![Go Reference](https://pkg.go.dev/badge/github.com/phcp-tech/common-library-golang.svg)](https://pkg.go.dev/github.com/phcp-tech/common-library-golang)\r\n[![LICENSE](https://img.shields.io/badge/license-Apache--2.0-green.svg)](https://github.com/phcp-tech/common-library-golang/blob/main/LICENSE)\r\n![CI](https://github.com/phcp-tech/common-library-golang/actions/workflows/deploy-build-test.yml/badge.svg)\r\n[![codecov](https://codecov.io/gh/phcp-tech/common-library-golang/branch/main/graph/badge.svg)](https://app.codecov.io/gh/phcp-tech/common-library-golang)\r\n\r\nCommon-library-golang is a collection of functional components used within the PHCP ecosystem, providing numerous components for microservice development, it provides some out-of-the-box functions, such as environment, log, database, etc. To make it more widely available, it is now open-sourced under the Apache license.\r\n\r\n## Requirements\r\n\r\n- Go 1.25+\r\n\r\n## Installation\r\n\r\n```bash\r\ngo get github.com/phcp-tech/common-library-golang\r\n```\r\n\r\n## Build and Test\r\n\r\n```bash\r\ngo mod tidy\r\ngo vet ./...\r\ngo build ./...\r\n```\r\n\r\n### Short mode test — fast CI verification\r\n\r\nSome tests start a real TCP listener (e.g. `httpserver` integration tests). Pass\r\n`-short` to skip them and keep the test run lightweight:\r\n\r\n```bash\r\ngo test ./... -short\r\n```\r\n\r\n### Full test run — including integration tests\r\n\r\n```bash\r\ngo test ./...\r\n```\r\n\r\n### Run test with coverage\r\n\r\n```bash\r\n# All packages\r\ngo test ./... -cover -timeout 60s\r\n\r\n```\r\n\r\n## Packages\r\n\r\n| Group | Package | Import path | Description |\r\n|-------|---------|-------------|-------------|\r\n| Basic | [`env`](#env--configuration-management) | `.../common-library-golang/env` | TOML config + environment variable loader |\r\n| Basic | [`log`](#log--structured-logging) | `.../common-library-golang/log` | Structured JSON logger with file rotation and ringbuf |\r\n| Basic | [`app`](#app--application-utilities) | `.../common-library-golang/app` | Application health check, and version metadata |\r\n| Basic | [`shutdown`](#shutdown--graceful-shutdown) | `.../common-library-golang/shutdown` | Block until OS signal or programmatic trigger, then continue for cleanup |\r\n| Basic | [`ringbuf`](#ringbuf--ring-buffers) | `.../common-library-golang/ringbuf` | Lock-free ring buffers (SPSC and MPSC) |\r\n| Basic | [`maps`](#maps--thread-safe-concurrent-maps) | `.../common-library-golang/maps` | Thread-safe generic concurrent maps with pluggable replacement strategies |\r\n| Basic | [`cgroup`](#cgroup--linux-resource-limits) | `.../common-library-golang/cgroup` | Read CPU and memory resource limits from cgroup v2 (Linux only; returns 0 on other platforms) |\r\n| Basic | [`metrics`](#metrics--runtime-metrics-snapshot) | `.../common-library-golang/metrics` | Runtime and system metrics snapshot (CPU, memory, goroutines, cgroup limits, uptime) |\r\n| Database | [`redis`](#redis--redis-client) | `.../common-library-golang/redis` | Redis client (standalone and cluster) with connection pool and key scan utilities |\r\n| Database | [`dbsqlc/postgres`](#dbsqlcpostgres--postgresql-connection-pool) | `.../common-library-golang/dbsqlc/postgres` | PostgreSQL connection pool via pgx/v5 |\r\n| Database | [`dbsqlc/sqlite`](#dbsqlcsqlite--sqlite-connection) | `.../common-library-golang/dbsqlc/sqlite` | SQLite connection via pure-Go modernc driver |\r\n| Database | [`dbsqlc/sqlite/vfs`](#dbsqlcsqlitevfs--embedded-sqlite-via-vfs) | `.../common-library-golang/dbsqlc/sqlite/vfs` | SQLite over embedded FS via VFS (binary-embedded databases) |\r\n| Network | [`network`](#network--network-utilities) | `.../common-library-golang/network` | Network utilities helpers |\r\n| Network | [`auth`](#auth--casbin-rbac-authorisation) | `.../common-library-golang/auth` | Casbin RBAC authorisation middleware for Gin |\r\n| Network | [`token`](#token--jwt-authentication) | `.../common-library-golang/token` | JWT access/refresh token creation, parsing, and Gin middleware |\r\n| Network | [`gin`](#gin--gin-engine-factory) | `.../common-library-golang/gin` | Gin engine factory with slog request logging and CORS |\r\n| Network | [`gin/pprof`](#ginpprof--profiling-endpoints) | `.../common-library-golang/gin/pprof` | Optional pprof profiling endpoints for Gin (explicit opt-in) |\r\n| Network | [`httpclient`](#httpclient--resty-http-client) | `.../common-library-golang/httpclient` | Resty-based HTTP client with retry, JWT auth, and JSON helpers |\r\n| Network | [`httpclient/retryable`](#httpclientretryable--retryable-http-client) | `.../common-library-golang/httpclient/retryable` | hashicorp/go-retryablehttp wrapper returning standard *http.Client |\r\n| Network | [`httpserver`](#httpserver--production-httphttps-server) | `.../common-library-golang/httpserver` | Production HTTP/HTTPS server with timeouts and graceful shutdown |\r\n| Network | [`httpserver/lambda`](#httpserverlambda--aws-lambda-adapter) | `.../common-library-golang/httpserver/lambda` | AWS Lambda adapter implementing httpserver.Runner (explicit opt-in) |\r\n\r\n---\r\n\r\n## env — Configuration Management\r\n\r\nLoads a TOML config file and merges OS environment variables on top.\r\nBuilt on [koanf](https://github.com/knadh/koanf). Implements the singleton pattern:\r\nonly the first `InitEnv` call takes effect.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/env\"\r\n\r\n// Call once at startup before any Env() usage.\r\nif err := env.InitEnv(\"config.toml\"); err != nil {\r\n    log.Fatal(err)\r\n}\r\n\r\nhost := env.Env().String(\"server.host\")\r\nport := env.Env().Int(\"server.port\")\r\n```\r\n\r\nFor single-binary deployments the config file can be embedded at compile time:\r\n\r\n```go\r\n//go:embed config.toml\r\nvar configFS embed.FS\r\n\r\nenv.InitEnv(\"config.toml\", \u0026configFS)\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/env#pkg-examples).\r\n\r\n---\r\n\r\n## log — Structured Logging\r\n\r\nStructured JSON logging via `log/slog` with UTC timestamps.\r\nFile writes are fully **asynchronous**: the caller returns immediately after pushing the formatted entry into an internal `RingMPSC` buffer; a dedicated consumer goroutine performs the actual I/O. This makes the package suitable for **high-throughput, latency-sensitive scenarios** where blocking on disk I/O is unacceptable.\r\n\r\n**`InitLog` must be called once at application startup before any log function.**\r\nOmit the argument for stdout output at INFO level; pass a `Config` to customise.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/log\"\r\n\r\n// Stdout mode at default INFO level.\r\nlog.InitLog()\r\nlog.Info(\"application started\")\r\nlog.Infof(\"listening on port %d\", 8080)\r\nlog.InfoWith(\"request\", \"method\", \"GET\", \"path\", \"/api/v1\", \"status\", 200)\r\n\r\n// Stdout mode with custom level.\r\nlog.InitLog(\u0026log.Config{Level: \"debug\"})\r\n\r\n// File mode: set FilePath to enable rotating file logging.\r\nlog.InitLog(\u0026log.Config{\r\n    Level:      \"info\",\r\n    FilePath:   \"/var/log/app.log\",\r\n    MaxSizeMB:  100,\r\n    MaxBackups: 7,\r\n    MaxAgeDays: 30,\r\n    Compress:   true,\r\n})\r\ndefer log.Close() // flush async buffer and close file on shutdown\r\n```\r\n\r\nAvailable log functions: `Debug` / `Info` / `Warn` / `Error` and their `f` (format) and `With` (structured key-value) variants. Log level can be changed at runtime with `SetLevel`.\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/log#pkg-examples).\r\n\r\n---\r\n\r\n## app — Application Utilities\r\n\r\nLightweight helpers for application health checks, version metadata. All functions read from `env.Env()` and require\r\n`env.InitEnv` to be called once at application startup.\r\n\r\n### Health endpoint\r\n\r\n```go\r\n// Returns Health{Name, Status} where Status is 2 when PostgreSQL is reachable,\r\n// 0 when it is not. Intended for a /health HTTP endpoint.\r\nh := app.GetHealth()\r\nif h.Status == 2 {\r\n    c.JSON(200, h)\r\n} else {\r\n    c.JSON(503, h)\r\n}\r\n```\r\n\r\n### Version endpoint\r\n\r\n```go\r\n// Returns Version{Name, Version, Environment, GoVersion, BuildInfo} populated\r\n// from env config and the embedded Go build info. Intended for a /version endpoint.\r\nv := app.GetVersion()\r\nc.JSON(200, v)\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/app#pkg-examples).\r\n\r\n---\r\n\r\n## shutdown — Graceful Shutdown\r\n\r\nTwo primitives for application shutdown coordination:\r\n\r\n- **`Wait`** blocks the calling goroutine until an OS signal (`SIGINT`, `SIGTERM`, `SIGHUP`, `SIGQUIT`) or `Trigger` is called. After it returns, the caller performs cleanup and exits.\r\n- **`Trigger`** unblocks `Wait` programmatically from any goroutine — useful for a `/shutdown` HTTP endpoint or a metrics failure handler. Safe to call multiple times.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/shutdown\"\r\n\r\n// In main: start services, then block until shutdown.\r\nshutdown.Wait()\r\n\r\n// Cleanup runs here (or via defer before Wait).\r\nrunner.Shutdown(ctx)\r\n```\r\n\r\n```go\r\n// From a /shutdown HTTP endpoint or metrics failure handler.\r\nshutdown.Trigger()\r\n```\r\n\r\n\u003e **Note:** `Trigger` has no effect when the process is forcibly terminated by the OS\r\n\u003e (e.g. IDE stop button on Windows calls `TerminateProcess` — no signal is delivered).\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/shutdown#pkg-examples).\r\n\r\n---\r\n\r\n## ringbuf — Ring Buffers\r\n\r\nHigh-performance fixed-capacity ring buffers for producer-consumer pipelines.\r\n\r\n| Type | Use case | Thread safety |\r\n|------|----------|---------------|\r\n| `RingSPSC` | Single producer, single consumer | Lock-free (atomic only) |\r\n| `RingMPSC` | Multiple producers, single consumer | Mutex on producer side |\r\n\r\nBoth types support an optional `ProcessFunc` that starts a consumer goroutine\r\nautomatically, or manual `Pop` / `TryPop` for caller-managed consumption.\r\n`Push` blocks when the buffer is full (backpressure); `TryPush` returns false\r\nimmediately.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/ringbuf\"\r\n\r\n// SPSC — single producer, automatic consumer goroutine\r\nrb := ringbuf.NewRingSPSC(ringbuf.RingSPSCConfig[string]{\r\n    Capacity:    1024,\r\n    ProcessFunc: func(s string) { fmt.Println(s) },\r\n})\r\nrb.Push(\"hello\")\r\nrb.Close() // drain and wait for consumer to finish\r\n\r\n// MPSC — multiple producers, automatic consumer goroutine\r\nrb := ringbuf.NewRingMPSC(ringbuf.RingMPSCConfig[[]byte]{\r\n    Capacity:    4096,\r\n    ProcessFunc: func(b []byte) { os.Stdout.Write(b) },\r\n})\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/ringbuf#pkg-examples).\r\n\r\n### Performance\r\n\r\nBenchmarks run with `go test -bench=. -benchtime=3s -benchmem`.\r\nAll operations produce **zero heap allocations**.\r\n\r\n**Test environment**\r\n\r\n| | |\r\n|---|---|\r\n| CPU | 11th Gen Intel® Core™ i7-11850H @ 2.50 GHz (8 cores / 16 threads) |\r\n| RAM | 32 GB |\r\n| OS | Windows 11 Enterprise |\r\n| Go | 1.26.2 windows/amd64 |\r\n\r\n**Results**\r\n\r\n| Benchmark | ns/op | Throughput | Allocs |\r\n|-----------|------:|----------:|-------:|\r\n| `SPSC Push` (1P-1C, blocking) | 76.65 | ~13.0 M ops/s | 0 |\r\n| `SPSC TryPush` (1P-1C, non-blocking) | 87.91 | ~11.4 M ops/s | 0 |\r\n| `SPSC ProducerConsumer` (end-to-end with ProcessFunc) | 83.72 | ~11.9 M ops/s | 0 |\r\n| `SPSC Push string` (realistic log payload) | 91.06 | ~11.0 M ops/s | 0 |\r\n| `MPSC Push` (1 producer) | 151.1 | ~6.6 M ops/s | 0 |\r\n| `MPSC Push` (4 producers concurrent) | 192.2 | ~5.2 M ops/s | 0 |\r\n| `MPSC Push` (8 producers concurrent) | 200.7 | ~5.0 M ops/s | 0 |\r\n| `MPSC ProducerConsumer` (4P end-to-end) | 197.5 | ~5.1 M ops/s | 0 |\r\n| `Go channel` (buffered 4096, reference) | 126.3 | ~7.9 M ops/s | 0 |\r\n\r\n**Key observations**\r\n\r\n- SPSC is **~1.6× faster** than a buffered Go channel for the same single-producer / single-consumer pattern.\r\n- MPSC trades some throughput for multi-producer safety via a mutex; with 8 concurrent producers it remains above **5 M ops/s**.\r\n- Throughput scales gracefully under producer contention: going from 1 to 8 producers adds only ~33% latency per item.\r\n- Both types maintain **zero allocations per operation**, making them suitable as the async I/O backbone for the `log` package.\r\n\r\n---\r\n\r\n## maps — Thread-Safe Concurrent Maps\r\n\r\nThread-safe generic concurrent maps backed by\r\n[orcaman/concurrent-map](https://github.com/orcaman/concurrent-map) with\r\npluggable replacement strategies.\r\n\r\nTwo implementations are provided:\r\n\r\n| Type | Key | Value | Strategy |\r\n|------|-----|-------|----------|\r\n| `CMap` | `string` (fixed) | `int64` (fixed) | Greater-value wins (built-in) |\r\n| `CMapGen[K, V]` | any `comparable` | any | Configurable via `SetDefaultCompare` or `SetDefaultStrategy` |\r\n\r\nBuilt-in strategy types: `NumericGreaterStrategy`, `AlwaysReplaceStrategy`, `TimestampStrategy`.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/maps\"\r\n\r\n// Generic map — configure a default compare function.\r\nm := maps.NewCMapGen[string, int64]()\r\nm.SetDefaultCompare(func(old, new int64) bool { return new \u003e old })\r\n\r\nm.Set(\"EURUSD\", 10500)\r\nm.Replace(\"EURUSD\", 10600)       // stored: 10600 \u003e 10500\r\nm.ReplaceAlways(\"EURUSD\", 9000)  // always stored\r\nm.ReplaceIfNotExists(\"GBPUSD\", 12800) // stored only if key absent\r\n\r\n// Atomic read-modify-write.\r\nm.UpsertWithCallback(\"USDJPY\", 15100, func(exists bool, old, new int64) int64 {\r\n    if !exists || new \u003e old { return new }\r\n    return old\r\n})\r\n\r\n// Fixed string→int64 map (no configuration needed).\r\ncm := maps.NewCMap()\r\ncm.Set(\"tick\", 10000)\r\ncm.Replace(\"tick\", 10050) // stored: 10050 \u003e 10000\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/maps#pkg-examples).\r\n\r\n### Performance\r\n\r\nBenchmarks run with `go test -bench=. -benchtime=3s -benchmem`.\r\n\r\n**Test environment** — same machine as ringbuf benchmarks:\r\nIntel® Core™ i7-11850H @ 2.50 GHz · 8 cores / 16 threads · 32 GB RAM · Go 1.26.2 / Windows 11\r\n\r\n**CMap** (fixed `string→int64`, built-in greater-value strategy)\r\n\r\n| Benchmark | ns/op | Throughput | B/op | Allocs |\r\n|-----------|------:|----------:|-----:|-------:|\r\n| `Set` | 33.01 | ~30.3 M ops/s | 0 | 0 |\r\n| `Get` | 15.68 | ~63.8 M ops/s | 0 | 0 |\r\n| `Replace` | 43.42 | ~23.0 M ops/s | 0 | 0 |\r\n| `Set` (parallel, 16 goroutines) | 90.67 | ~11.0 M ops/s | 0 | 0 |\r\n| `Replace` (parallel, 16 goroutines) | 434.8 | ~2.3 M ops/s | 0 | 0 |\r\n\r\n**CMapGen** (generic `[K comparable, V any]`)\r\n\r\n| Benchmark | ns/op | Throughput | B/op | Allocs | Note |\r\n|-----------|------:|----------:|-----:|-------:|------|\r\n| `Set` | 94.20 | ~10.6 M ops/s | 0 | 0 | |\r\n| `Get` | 60.54 | ~16.5 M ops/s | 0 | 0 | |\r\n| `Replace` (default strategy) | 137.0 | ~7.3 M ops/s | 32 | 3 | ⚠ fmt.Sprint fallback allocates |\r\n| `ReplaceWithCompare` | 52.94 | ~18.9 M ops/s | 0 | 0 | recommended |\r\n| `ReplaceAlways` | 29.78 | ~33.6 M ops/s | 0 | 0 | |\r\n| `UpsertWithCallback` | 58.68 | ~17.0 M ops/s | 0 | 0 | |\r\n| `Set` (parallel, 16 goroutines) | 74.32 | ~13.5 M ops/s | 0 | 0 | |\r\n| `Replace` (parallel, 16 goroutines) | 81.61 | ~12.3 M ops/s | 32 | 3 | ⚠ see above |\r\n| Mixed read/write (parallel) | 26.08 | ~38.3 M ops/s | 10 | 1 | |\r\n\r\n**`sync.Map`** (stdlib reference)\r\n\r\n| Benchmark | ns/op | Throughput | B/op | Allocs |\r\n|-----------|------:|----------:|-----:|-------:|\r\n| `Store` | 60.96 | ~16.4 M ops/s | 56 | 1 |\r\n| `Load` | 10.66 | ~93.8 M ops/s | 0 | 0 |\r\n| `Store` (parallel, 16 goroutines) | 103.7 | ~9.6 M ops/s | 56 | 1 |\r\n\r\n**Key observations**\r\n\r\n- `CMap.Set` is **~1.8× faster** than `sync.Map.Store` and allocates nothing.\r\n- `CMapGen.Replace` with a typed compare function (`ReplaceWithCompare` / `SetDefaultCompare`) is **zero-allocation**; the no-argument `Replace()` fallback uses `fmt.Sprint` internally and produces 3 allocations — always call `SetDefaultCompare` or `SetDefaultStrategy` at construction time.\r\n- `CMapGen.ReplaceAlways` is the fastest write path (~33.6 M ops/s) when no conditional logic is needed.\r\n- Under 16-goroutine parallel write contention `CMap.Replace` degrades to ~2.3 M ops/s due to single-key hot-spot; spreading writes across many keys restores throughput.\r\n\r\n---\r\n\r\n## cgroup — Linux Resource Limits\r\n\r\nReads CPU and memory resource limits from the **cgroup v2** unified hierarchy\r\n(`/sys/fs/cgroup`). Intended for containerised workloads (Kubernetes, Docker)\r\nwhere the process runs inside a cgroup with configured CPU and memory constraints.\r\n\r\nOn **non-Linux platforms** (macOS, Windows) all functions return `(0, nil)` — no\r\ncgroup filesystem is available and no error is raised.\r\n\r\n| Function | cgroup v2 file | Returns |\r\n|----------|---------------|---------|\r\n| `CPULimitMilli()` | `cpu.max` | CPU limit in millicores; 0 = unlimited |\r\n| `CPURequestMilli()` | `cpu.weight` | CPU request in millicores via weight→shares→mCPU |\r\n| `MemoryLimitBytes()` | `memory.max` | Memory limit in bytes; 0 = unlimited |\r\n| `MemoryRequestBytes()` | `memory.low` | Memory soft limit in bytes; 0 = not set |\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/cgroup\"\r\n\r\n// Read CPU limit and cap GOMAXPROCS accordingly.\r\nif milli, err := cgroup.CPULimitMilli(); err == nil \u0026\u0026 milli \u003e 0 {\r\n    cpus := milli / 1000\r\n    if cpus \u003c 1 {\r\n        cpus = 1\r\n    }\r\n    runtime.GOMAXPROCS(cpus)\r\n}\r\n\r\n// Size an in-process cache as 25 % of the container memory limit.\r\nif limitBytes, err := cgroup.MemoryLimitBytes(); err == nil \u0026\u0026 limitBytes \u003e 0 {\r\n    cacheBytes := limitBytes / 4\r\n    cache.SetMaxSize(cacheBytes)\r\n}\r\n```\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/cgroup#pkg-examples).\r\n\r\n---\r\n\r\n## metrics — Runtime Metrics Snapshot\r\n\r\nCollects a one-shot snapshot of key runtime and system metrics as a flat\r\n`[]NameValue` slice, suitable for a `/metrics` or `/health` HTTP endpoint.\r\n\r\nEach call samples **CPU usage over one second** via `gopsutil`, so it is\r\nintended for periodic polling (e.g. every 10–30 s), not hot-path use.\r\n\r\n| Metric name | Description |\r\n|-------------|-------------|\r\n| `cpuPercent` | Process CPU usage (%) across all cores, sampled over 1 s |\r\n| `memorySize` | Resident set size (RSS) in MiB |\r\n| `threads` | OS thread count |\r\n| `goroutines` | Live goroutine count |\r\n| `gomaxprocs` | `runtime.GOMAXPROCS(0)` |\r\n| `numCPU` | `runtime.NumCPU()` |\r\n| `cpuRequest` | cgroup v2 CPU request in millicores (0 if not set or non-Linux) |\r\n| `cpuLimit` | cgroup v2 CPU limit in millicores (0 if unlimited or non-Linux) |\r\n| `memoryRequest` | cgroup v2 memory soft limit in bytes (0 if not set or non-Linux) |\r\n| `memoryLimit` | cgroup v2 memory limit in bytes (0 if unlimited or non-Linux) |\r\n| `age` | Process uptime formatted as `Xd Xh Xm Xs` |\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/metrics\"\r\n\r\n// Periodic metrics poll — call from a background goroutine.\r\nsnapshot := metrics.GetMetrics()\r\n\r\n// Look up a specific entry.\r\nfor _, nv := range snapshot {\r\n    if nv.Name == \"goroutines\" {\r\n        slog.Info(\"runtime\", \"goroutines\", nv.Value)\r\n    }\r\n}\r\n\r\n// Serialize to JSON for a /health endpoint.\r\nb, _ := json.Marshal(snapshot)\r\nw.Write(b)\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/metrics#pkg-examples).\r\n\r\n---\r\n\r\n## redis — Redis Client\r\n\r\nThread-safe Redis client supporting both **standalone** and **cluster** modes,\r\nbacked by [go-redis/v9](https://github.com/redis/go-redis).\r\nConnection pool settings (`PoolSize`, `MinIdleConns`) are configurable via `Config`\r\nwith sensible defaults (100 / 5). The caller reads values from `env.Env()` at the\r\ncomposition root — this package has no dependency on env.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/redis\"\r\n\r\n// Standalone mode (single address).\r\ncli := redis.NewRedisClient(\u0026redis.Config{\r\n    Clusters: []string{env.Env().String(\"redis.addr\")},\r\n    Password: env.Env().String(\"redis.password\"),\r\n    DB:       env.Env().Int(\"redis.db\"),\r\n})\r\ndefer cli.Close()\r\n\r\n// Cluster mode — more than one address enables cluster automatically.\r\ncli := redis.NewRedisClient(\u0026redis.Config{\r\n    Clusters:     env.Env().Strings(\"redis.clusters\"),\r\n    PoolSize:     200,\r\n    MinIdleConns: 10,\r\n})\r\n\r\n// Basic operations.\r\ncli.Set(ctx, \"key\", \"value\", 5*time.Minute)\r\nval, err := cli.Get(ctx, \"key\")\r\ncli.Del(ctx, \"key\")\r\ncli.Unlink(ctx, \"key\") // async deletion — preferred for large keys\r\n\r\n// Remove all keys starting with a prefix.\r\ncli.CleanCache(ctx, \"user:42:\")\r\n\r\n// Count matching keys across all nodes.\r\nn, err := cli.GetKeysCount(ctx, \"session:*\")\r\n```\r\n\r\nImplements the singleton pattern via `InitDefault` / `Default`.\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/redis#pkg-examples).\r\n\r\n---\r\n\r\n## dbsqlc/postgres — PostgreSQL Connection Pool\r\n\r\npgx/v5 connection pool for use with [sqlc](https://sqlc.dev/) (`sql_package: \"pgx/v5\"`).\r\nPool creation is **lazy**: `NewPostgres` returns immediately without establishing any\r\nconnections, so no live server is required at startup.\r\nImplements the singleton pattern via `InitDefault` / `Default`.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/dbsqlc/postgres\"\r\n\r\n// Singleton mode: call once at startup.\r\nerr := postgres.InitDefault(\u0026postgres.Config{\r\n    Host:            \"localhost\",\r\n    Port:            \"5432\",\r\n    Database:        \"mydb\",\r\n    Username:        \"user\",\r\n    Password:        \"pass\",\r\n    MaxOpenConns:    100,\r\n    MaxIdleConns:    25,\r\n    ConnMaxLifetime: 60, // minutes\r\n    ConnMaxIdletime: 10, // minutes\r\n    SearchPath:      \"myschema\", // optional\r\n})\r\nif err != nil {\r\n    log.Fatal(err)\r\n}\r\n\r\npool := postgres.Default() // *pgxpool.Pool, pass to sqlc Queries\r\n```\r\n\r\nFor cases that require multiple pools, use `NewPostgres` directly instead of the singleton.\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/dbsqlc/postgres#pkg-examples).\r\n\r\n---\r\n\r\n## dbsqlc/sqlite — SQLite Connection\r\n\r\nPure-Go SQLite driver ([modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite), no CGO required).\r\nFor use with [sqlc](https://sqlc.dev/) (`sql_package: \"database/sql\"`).\r\nImplements the singleton pattern via `InitDefault` / `Default`.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/dbsqlc/sqlite\"\r\n\r\n// In-memory database (tests and short-lived operations).\r\ndb, err := sqlite.NewSQLite(\u0026sqlite.Config{Path: \":memory:\"})\r\n\r\n// File-based database with WAL mode and foreign key enforcement.\r\nerr := sqlite.InitDefault(\u0026sqlite.Config{\r\n    Path: \"file:app.db?_journal_mode=WAL\u0026_foreign_keys=on\",\r\n})\r\nif err != nil {\r\n    log.Fatal(err)\r\n}\r\n\r\ndb := sqlite.Default() // *sql.DB, pass to sqlc Queries\r\n```\r\n\r\nSQLite allows only one writer at a time. `NewSQLite` calls `SetMaxOpenConns(1)` automatically\r\nto prevent `database is locked` errors when WAL mode is not in use.\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/dbsqlc/sqlite#pkg-examples).\r\n\r\n---\r\n\r\n## dbsqlc/sqlite/vfs — Embedded SQLite via VFS\r\n\r\nOpens a SQLite database that is **embedded inside the Go binary** using\r\n[modernc.org/sqlite/vfs](https://pkg.go.dev/modernc.org/sqlite/vfs) and Go's\r\n`embed.FS`. The database file must reside at `config/sqlite.db` inside the embedded\r\nfilesystem.\r\n\r\n**Import this sub-package only when the database is distributed as part of the binary.**\r\nFor regular file-based databases use `dbsqlc/sqlite` instead.\r\n\r\n```go\r\nimport sqlitevfs \"github.com/phcp-tech/common-library-golang/dbsqlc/sqlite/vfs\"\r\n\r\n//go:embed config/sqlite.db\r\nvar sqliteFS embed.FS\r\n\r\n// Singleton mode: call once at startup.\r\nif err := sqlitevfs.InitDefault(\u0026sqliteFS); err != nil {\r\n    log.Fatal(err)\r\n}\r\n\r\ndb := sqlitevfs.Default() // *sql.DB, pass to sqlc-generated Queries\r\n```\r\n\r\nFor cases that require multiple VFS connections, use `New` directly instead of the singleton.\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/dbsqlc/sqlite/vfs#pkg-examples).\r\n\r\n---\r\n## network — Network Utilities\r\n\r\nHelpers for request IP extraction, local interface inspection, and IPv4 ↔ uint32 conversion.\r\n\r\n### IP address helpers\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/network\"\r\n\r\n// Real client IP — inspects X-Forwarded-For → X-Real-IP → RemoteAddr.\r\n// Returns the first address in X-Forwarded-For when multiple proxies are chained.\r\n// \"::1\" is normalised to \"127.0.0.1\".\r\nip := network.GetRemoteIp(req)\r\n\r\n// All non-loopback IPv4 addresses on the local machine.\r\naddrs := network.GetLocalIpAddress()\r\n```\r\n\r\n### IPv4 ↔ uint32 conversion\r\n\r\nTwo byte orders are supported:\r\n\r\n| Function | Byte order | Typical use |\r\n|----------|-----------|-------------|\r\n| `Ip2IntWithBigEndian` | Big-endian (network order) | Standard TCP/IP, databases |\r\n| `Int2IpWithBigEndian` | Big-endian | Same as above |\r\n| `Ip2IntWithLittleEndian` | Little-endian | MT4 / MT5 trading platforms |\r\n| `Int2IpWithLittleEndian` | Little-endian | Same as above |\r\n\r\n```go\r\n// Big-endian (network byte order): \"1.2.3.4\" → 0x01020304\r\nn := network.Ip2IntWithBigEndian(\"1.2.3.4\")   // → 16909060\r\nip := network.Int2IpWithBigEndian(0x01020304)  // → \"1.2.3.4\"\r\n\r\n// Little-endian (MT4/MT5 format): \"1.2.3.4\" → 0x04030201\r\nn := network.Ip2IntWithLittleEndian(\"1.2.3.4\")   // → 67305985\r\nip := network.Int2IpWithLittleEndian(0x04030201)  // → \"1.2.3.4\"\r\n\r\n// Both return 0 / \"\" for empty, invalid, or IPv6 input.\r\n```\r\n\r\n### Address validation\r\n\r\n```go\r\n// IsValidAddr checks if the string is a valid IP address (with or without port)\r\n// or a resolvable hostname.\r\nnetwork.IsValidAddr(\"192.168.1.1:8080\") // true\r\nnetwork.IsValidAddr(\"192.168.1.1\")      // true\r\nnetwork.IsValidAddr(\"example.com:443\")  // true (DNS lookup)\r\nnetwork.IsValidAddr(\"999.999.999.999\")  // false\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/network#pkg-examples).\r\n\r\n---\r\n\r\n## auth — Casbin RBAC Authorisation\r\n\r\nRole-based access control (RBAC) Gin middleware backed by\r\n[Casbin](https://casbin.org/). Enforces policy using **method-2 semantics**:\r\nevery role in the user's role list must pass the policy check — if any role\r\nis denied, the request is rejected with HTTP 403 Forbidden.\r\n\r\n`InitCasbin` must be called once at application startup before `Authorize` is\r\nregistered. Model and policy can be loaded from in-memory strings (`fs=true`)\r\nor from files on disk (`fs=false`).\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/auth\"\r\n\r\n// Load model and policy from in-memory strings (e.g. embedded at build time).\r\nif err := auth.InitCasbin(true, modelString, policyString); err != nil {\r\n    log.Fatal(err)\r\n}\r\n\r\n// Load model and policy from files.\r\nif err := auth.InitCasbin(false, \"model.conf\", \"policy.csv\"); err != nil {\r\n    log.Fatal(err)\r\n}\r\n\r\n// Register as a Gin middleware after token.Authenticate.\r\n// It reads roles from the \"userInfo\" context key set by token.Authenticate.\r\nr := gin.New()\r\nr.Use(token.Authenticate())\r\nr.Use(auth.Authorize())\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/auth#pkg-examples).\r\n\r\n---\r\n\r\n## token — JWT Authentication\r\n\r\nHS256 JWT access and refresh token creation, parsing, and a Gin bearer-token middleware.\r\nBuilt on [golang-jwt/jwt](https://github.com/golang-jwt/jwt).\r\n\r\n**`InitToken` must be called once at application startup** before any token function.\r\nThe secrets and issuer are typically read from `env.Env()` after `env.InitEnv()`.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/token\"\r\n\r\n// Initialise once at startup (composition root), after env.InitEnv().\r\ntoken.InitToken(\r\n    env.Env().String(\"jwt.issuer\"),             // e.g. \"phcp\"\r\n    env.Env().String(\"jwt.access.secretcode\"),  // access token signing key\r\n    env.Env().String(\"jwt.refresh.secretcode\"), // refresh token signing key\r\n)\r\n\r\n// Create a short-lived access token (valid for 1 hour).\r\ntok, err := token.CreateToken(userId, username, productId, roles, time.Hour)\r\n\r\n// Validate and parse an access token from an incoming request.\r\nuser, err := token.ParseToken(tok)\r\nfmt.Println(user.Username, user.UserId, user.Roles)\r\n\r\n// Create a long-lived refresh token (no roles embedded).\r\nrefresh, err := token.CreateRefreshToken(userId, username, productId, 24*time.Hour)\r\n\r\n// Register as a Gin middleware; stores LoginUser in context under key \"userInfo\".\r\nr := gin.New()\r\nr.Use(token.Authenticate())\r\n```\r\n\r\n`Authenticate` aborts with HTTP 401 if the `Authorization: Bearer \u003ctoken\u003e` header is\r\nmissing, malformed, or carries an invalid/expired token.\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/token#pkg-examples).\r\n\r\n---\r\n\r\n## gin — Gin Engine Factory\r\n\r\nPre-configured [Gin](https://github.com/gin-gonic/gin) engine with structured slog-based\r\nrequest logging (`slog-gin`) and optional CORS support. Always runs in `ReleaseMode`.\r\n\r\n`InitGin` is the single entry point. Pass a slice of allowed origins to enable CORS;\r\nentries containing `*` are treated as single-level wildcard patterns\r\n(e.g. `https://*.example.com` matches `https://api.example.com` but not `https://a.b.example.com`).\r\n\r\n```go\r\nimport libgin \"github.com/phcp-tech/common-library-golang/gin\"\r\n\r\n// No CORS.\r\nrouter := libgin.InitGin(nil)\r\n\r\n// Exact origins and wildcard patterns can be mixed.\r\nrouter := libgin.InitGin([]string{\r\n    \"https://app.example.com\",   // exact\r\n    \"https://*.example.com\",     // wildcard: root + any single subdomain\r\n})\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/gin#pkg-examples).\r\n\r\n---\r\n\r\n## gin/pprof — Profiling Endpoints\r\n\r\nRegisters Go runtime pprof endpoints on a Gin engine via\r\n[gin-contrib/pprof](https://github.com/gin-contrib/pprof).\r\n\r\n**Import this sub-package only in services that require profiling.**\r\nImporting it is an explicit opt-in — it does not affect services that only import `gin`.\r\n\r\nTwo route groups are mounted:\r\n\r\n| Path | Purpose |\r\n|------|---------|\r\n| `/debug/pprof/*` | Standard Go pprof path for direct access |\r\n| `\u003cpath\u003e/admin/pprof/*` | API-gateway-friendly alias |\r\n\r\n```go\r\nimport (\r\n    libgin   \"github.com/phcp-tech/common-library-golang/gin\"\r\n    ginpprof \"github.com/phcp-tech/common-library-golang/gin/pprof\"\r\n)\r\n\r\nrouter := libgin.InitGin(nil)\r\nginpprof.Mount(router, \"/api/v1\") // mounts /debug/pprof/* and /api/v1/admin/pprof/*\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/gin/pprof#pkg-examples).\r\n\r\n---\r\n\r\n## httpclient — Resty HTTP Client\r\n\r\nFeature-rich HTTP client built on [go-resty/resty](https://github.com/go-resty/resty)\r\nwith pre-configured retry, JWT bearer-token support, and automatic JSON handling.\r\nSuitable for structured service-to-service calls.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/httpclient\"\r\n\r\n// Default settings: Timeout=10s, RetryMax=3.\r\ncli := httpclient.NewHttpClient()\r\n\r\n// Custom settings — zero-value fields fall back to defaults.\r\ncli := httpclient.NewHttpClient(httpclient.Config{\r\n    Timeout:            15 * time.Second,\r\n    RetryMax:           5,\r\n    InsecureSkipVerify: true, // only for internal self-signed certs\r\n})\r\n\r\nresp, err := cli.Get(url, jwtToken, nil)\r\nresp, err := cli.Post(url, jwtToken, body)\r\nresp, err := cli.Put(url, jwtToken, body)\r\nresp, err := cli.Delete(url, jwtToken, body)\r\n\r\n// Access the underlying resty.Client for advanced use.\r\nrestyClient := cli.Client()\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/httpclient#pkg-examples).\r\n\r\n---\r\n\r\n## httpclient/retryable — Retryable HTTP Client\r\n\r\nWraps [hashicorp/go-retryablehttp](https://github.com/hashicorp/go-retryablehttp)\r\nand exposes it as a standard `*http.Client` with configurable retry and timeout.\r\nUse this sub-package when existing code already uses `net/http` directly and you\r\nneed to add retry behaviour without switching to resty.\r\n\r\n**Import this sub-package only when needed** — it pulls in the hashicorp library\r\nindependently of the parent `httpclient` package.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/httpclient/retryable\"\r\n\r\ncli := retryable.NewHttpClient(retryable.Config{\r\n    Timeout:  15 * time.Second,\r\n    RetryMax: 5,\r\n})\r\n\r\n// Obtain a standard *http.Client with retry built in.\r\nstdClient := cli.Client().StandardClient()\r\nresp, err := stdClient.Do(req)\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/httpclient/retryable#pkg-examples).\r\n\r\n---\r\n\r\n## httpserver — Production HTTP/HTTPS Server\r\n\r\nA production-ready HTTP/HTTPS server built on `net/http` with secure defaults.\r\nIt wraps `http.Server` directly (not `gin.Run()`) to provide:\r\n\r\n- **Configurable timeouts** — `ReadTimeout`, `WriteTimeout`, `IdleTimeout`, `ReadHeaderTimeout`\r\n- **TLS 1.2+ with strong cipher suites** — activated when `CrtFile` and `KeyFile` are set\r\n- **Graceful shutdown** — `Shutdown(ctx)` drains in-flight requests before stopping\r\n\r\nThe `Runner` interface unifies HTTP and Lambda modes so the composition root\r\nselects the backend and the rest of the application code is unchanged.\r\n\r\n```go\r\nimport \"github.com/phcp-tech/common-library-golang/httpserver\"\r\n\r\n// Plain HTTP with package defaults.\r\nrunner := httpserver.NewHttpServer(httpserver.Config{Port: \"8080\"})\r\n\r\n// HTTPS with custom timeouts.\r\nrunner := httpserver.NewHttpServer(httpserver.Config{\r\n    Port:        \"8443\",\r\n    CrtFile:     \"/etc/ssl/server.crt\",\r\n    KeyFile:     \"/etc/ssl/server.key\",\r\n    ReadTimeout: 15 * time.Second,\r\n    WriteTimeout: 0, // 0 = unlimited (required for file downloads)\r\n})\r\n\r\n// Start in a goroutine; block until OS signal, then shut down gracefully.\r\ngo func() { _ = runner.Start(ginRouter) }()\r\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\r\ndefer cancel()\r\n_ = runner.Shutdown(ctx)\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/httpserver#pkg-examples).\r\n\r\n---\r\n\r\n## httpserver/lambda — AWS Lambda Adapter\r\n\r\nImplements `httpserver.Runner` for AWS Lambda via\r\n[aws-lambda-go-api-proxy](https://github.com/awslabs/aws-lambda-go-api-proxy).\r\nIt bridges `APIGatewayProxyRequest` events to any `http.Handler` (including\r\n`*gin.Engine`) with no handler changes required.\r\n\r\n**Import this sub-package only for Lambda deployments** — it pulls in the AWS\r\nLambda SDK. Services that run as plain HTTP servers are unaffected.\r\n\r\n```go\r\nimport (\r\n    \"github.com/phcp-tech/common-library-golang/httpserver\"\r\n    lambdarunner \"github.com/phcp-tech/common-library-golang/httpserver/lambda\"\r\n)\r\n\r\n// Composition root selects the runner based on the deployment environment.\r\nvar runner httpserver.Runner\r\nif isLambda {\r\n    runner = lambdarunner.NewHttpServer()\r\n} else {\r\n    runner = httpserver.NewHttpServer(httpserver.Config{Port: port})\r\n}\r\n_ = runner.Start(ginRouter) // same call regardless of mode\r\n```\r\n\r\nSee [full examples](https://pkg.go.dev/github.com/phcp-tech/common-library-golang/httpserver/lambda#pkg-examples).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphcp-tech%2Fcommon-library-golang","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphcp-tech%2Fcommon-library-golang","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphcp-tech%2Fcommon-library-golang/lists"}