Skip to content

Commit 42708f7

Browse files
committed
pkg/sqlutil/pg: create package; expand env config
1 parent 249ef7a commit 42708f7

13 files changed

+784
-30
lines changed

go.mod

+13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/smartcontractkit/chainlink-common
33
go 1.21
44

55
require (
6+
github.com/XSAM/otelsql v0.29.0
67
github.com/confluentinc/confluent-kafka-go/v2 v2.3.0
78
github.com/dominikbraun/graph v0.23.0
89
github.com/fxamacker/cbor/v2 v2.5.0
@@ -14,6 +15,7 @@ require (
1415
github.com/hashicorp/go-hclog v1.5.0
1516
github.com/hashicorp/go-plugin v1.6.0
1617
github.com/invopop/jsonschema v0.12.0
18+
github.com/jackc/pgx/v4 v4.18.3
1719
github.com/jmoiron/sqlx v1.4.0
1820
github.com/jonboulle/clockwork v0.4.0
1921
github.com/jpillora/backoff v1.0.0
@@ -24,6 +26,7 @@ require (
2426
github.com/pelletier/go-toml/v2 v2.2.0
2527
github.com/prometheus/client_golang v1.17.0
2628
github.com/riferrei/srclient v0.5.4
29+
github.com/scylladb/go-reflectx v1.0.1
2730
github.com/shopspring/decimal v1.4.0
2831
github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c
2932
github.com/stretchr/testify v1.9.0
@@ -42,6 +45,16 @@ require (
4245
sigs.k8s.io/yaml v1.4.0
4346
)
4447

48+
require (
49+
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
50+
github.com/jackc/pgconn v1.14.3 // indirect
51+
github.com/jackc/pgio v1.0.0 // indirect
52+
github.com/jackc/pgpassfile v1.0.0 // indirect
53+
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
54+
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
55+
github.com/jackc/pgtype v1.14.0 // indirect
56+
)
57+
4558
require (
4659
github.com/bahlo/generic-list-go v0.2.0 // indirect
4760
github.com/beorn7/perks v1.0.1 // indirect

go.sum

+138
Large diffs are not rendered by default.

pkg/config/static/static.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package static
2+
3+
import (
4+
"os"
5+
"runtime/debug"
6+
)
7+
8+
// Unset is a sentinel value.
9+
const Unset = "unset"
10+
11+
// Version and Checksum are set at compile time via build arguments.
12+
var (
13+
// Program is updated to the full main program path if [debug.BuildInfo] is available.
14+
Program = os.Args[0]
15+
// Version is the semantic version of the build or Unset.
16+
Version = Unset
17+
// Checksum is the commit hash of the build or Unset.
18+
Checksum = Unset
19+
)
20+
21+
func init() {
22+
buildInfo, ok := debug.ReadBuildInfo()
23+
if ok {
24+
Program = buildInfo.Main.Path
25+
if Version == "" {
26+
Version = buildInfo.Main.Version
27+
}
28+
if Checksum == "" {
29+
Checksum = buildInfo.Main.Sum
30+
}
31+
}
32+
}
33+
34+
// Short returns a 7-character sha prefix and version, or Unset if blank.
35+
func Short() (shaPre string, ver string) {
36+
return short(Checksum, Version)
37+
}
38+
39+
func short(sha, ver string) (string, string) {
40+
if sha == "" {
41+
sha = Unset
42+
} else if len(sha) > 7 {
43+
sha = sha[:7]
44+
}
45+
if ver == "" {
46+
ver = Unset
47+
}
48+
return sha, ver
49+
}

pkg/logger/logger.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package logger
22

33
import (
4+
"fmt"
45
"reflect"
56
"testing"
67

78
"go.uber.org/zap"
89
"go.uber.org/zap/zapcore"
910
"go.uber.org/zap/zaptest"
1011
"go.uber.org/zap/zaptest/observer"
12+
13+
"github.com/smartcontractkit/chainlink-common/pkg/config/static"
1114
)
1215

1316
// Logger is a minimal subset of smartcontractkit/chainlink/core/logger.Logger implemented by go.uber.org/zap.SugaredLogger
@@ -51,9 +54,17 @@ func New() (Logger, error) { return defaultConfig.New() }
5154
func (c *Config) New() (Logger, error) {
5255
return NewWith(func(cfg *zap.Config) {
5356
cfg.Level.SetLevel(c.Level)
57+
cfg.InitialFields = map[string]interface{}{
58+
"version": staticShortVerSha(),
59+
}
5460
})
5561
}
5662

63+
func staticShortVerSha() string {
64+
sha, ver := static.Short() //TODO rename?
65+
return fmt.Sprintf("%s@%s", ver, sha)
66+
}
67+
5768
// NewWith returns a new Logger from a modified [zap.Config].
5869
func NewWith(cfgFn func(*zap.Config)) (Logger, error) {
5970
cfg := zap.NewProductionConfig()
@@ -76,7 +87,7 @@ func Test(tb testing.TB) Logger {
7687
zapcore.DebugLevel,
7788
),
7889
)
79-
return &logger{lggr.Sugar()}
90+
return &logger{lggr.With(zap.String("version", staticShortVerSha())).Sugar()}
8091
}
8192

8293
// TestSugared returns a new test SugaredLogger.

pkg/loop/config.go

+74-4
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,20 @@ import (
66
"os"
77
"strconv"
88
"strings"
9+
"time"
910

1011
"github.com/hashicorp/go-plugin"
1112
)
1213

1314
const (
14-
envDatabaseURL = "CL_DATABASE_URL"
15+
envDatabaseURL = "CL_DATABASE_URL"
16+
envDatabaseIdleInTxSessionTimeout = "CL_DATABASE_IDLE_IN_TX_SESSION_TIMEOUT"
17+
envDatabaseLockTimeout = "CL_DATABASE_LOCK_TIMEOUT"
18+
envDatabaseQueryTimeout = "CL_DATABASE_QUERY_TIMEOUT"
19+
envDatabaseLogSQL = "CL_DATABASE_LOG_SQL"
20+
envDatabaseMaxOpenConns = "CL_DATABASE_MAX_OPEN_CONNS"
21+
envDatabaseMaxIdleConns = "CL_DATABASE_MAX_IDLE_CONNS"
22+
1523
envPromPort = "CL_PROMETHEUS_PORT"
1624
envTracingEnabled = "CL_TRACING_ENABLED"
1725
envTracingCollectorTarget = "CL_TRACING_COLLECTOR_TARGET"
@@ -23,7 +31,13 @@ const (
2331
// EnvConfig is the configuration between the application and the LOOP executable. The values
2432
// are fully resolved and static and passed via the environment.
2533
type EnvConfig struct {
26-
DatabaseURL *url.URL
34+
DatabaseURL *url.URL
35+
DatabaseIdleInTxSessionTimeout time.Duration
36+
DatabaseLockTimeout time.Duration
37+
DatabaseQueryTimeout time.Duration
38+
DatabaseLogSQL bool
39+
DatabaseMaxOpenConns int
40+
DatabaseMaxIdleConns int
2741

2842
PrometheusPort int
2943

@@ -47,6 +61,12 @@ func (e *EnvConfig) AsCmdEnv() (env []string) {
4761
// DatabaseURL is optional
4862
if e.DatabaseURL != nil {
4963
injectEnv[envDatabaseURL] = e.DatabaseURL.String()
64+
injectEnv[envDatabaseIdleInTxSessionTimeout] = e.DatabaseIdleInTxSessionTimeout.String()
65+
injectEnv[envDatabaseLockTimeout] = e.DatabaseLockTimeout.String()
66+
injectEnv[envDatabaseQueryTimeout] = e.DatabaseQueryTimeout.String()
67+
injectEnv[envDatabaseLogSQL] = strconv.FormatBool(e.DatabaseLogSQL)
68+
injectEnv[envDatabaseMaxOpenConns] = strconv.Itoa(e.DatabaseMaxOpenConns)
69+
injectEnv[envDatabaseMaxIdleConns] = strconv.Itoa(e.DatabaseMaxIdleConns)
5070
}
5171

5272
for k, v := range e.TracingAttributes {
@@ -61,13 +81,39 @@ func (e *EnvConfig) AsCmdEnv() (env []string) {
6181

6282
// parse deserializes environment variables
6383
func (e *EnvConfig) parse() error {
64-
promPortStr := os.Getenv(envPromPort)
6584
var err error
6685
e.DatabaseURL, err = getDatabaseURL()
6786
if err != nil {
68-
return fmt.Errorf("failed to parse %s: %q", envDatabaseURL, err)
87+
return err
88+
}
89+
if e.DatabaseURL != nil {
90+
e.DatabaseIdleInTxSessionTimeout, err = getDatabaseIdleInTxSessionTimeout()
91+
if err != nil {
92+
return err
93+
}
94+
e.DatabaseLockTimeout, err = getDatabaseLockTimeout()
95+
if err != nil {
96+
return err
97+
}
98+
e.DatabaseQueryTimeout, err = getDatabaseQueryTimeout()
99+
if err != nil {
100+
return err
101+
}
102+
e.DatabaseLogSQL, err = getDatabaseLogSQL()
103+
if err != nil {
104+
return err
105+
}
106+
e.DatabaseMaxOpenConns, err = getDatabaseMaxOpenConns()
107+
if err != nil {
108+
return err
109+
}
110+
e.DatabaseMaxIdleConns, err = getDatabaseMaxIdleConns()
111+
if err != nil {
112+
return err
113+
}
69114
}
70115

116+
promPortStr := os.Getenv(envPromPort)
71117
e.PrometheusPort, err = strconv.Atoi(promPortStr)
72118
if err != nil {
73119
return fmt.Errorf("failed to parse %s = %q: %w", envPromPort, promPortStr, err)
@@ -164,3 +210,27 @@ func getDatabaseURL() (*url.URL, error) {
164210
}
165211
return u, nil
166212
}
213+
214+
func getDatabaseIdleInTxSessionTimeout() (time.Duration, error) {
215+
return time.ParseDuration(os.Getenv(envDatabaseIdleInTxSessionTimeout))
216+
}
217+
218+
func getDatabaseLockTimeout() (time.Duration, error) {
219+
return time.ParseDuration(os.Getenv(envDatabaseLockTimeout))
220+
}
221+
222+
func getDatabaseQueryTimeout() (time.Duration, error) {
223+
return time.ParseDuration(os.Getenv(envDatabaseQueryTimeout))
224+
}
225+
226+
func getDatabaseLogSQL() (bool, error) {
227+
return strconv.ParseBool(os.Getenv(envDatabaseLogSQL))
228+
}
229+
230+
func getDatabaseMaxOpenConns() (int, error) {
231+
return strconv.Atoi(os.Getenv(envDatabaseMaxOpenConns))
232+
}
233+
234+
func getDatabaseMaxIdleConns() (int, error) {
235+
return strconv.Atoi(os.Getenv(envDatabaseMaxIdleConns))
236+
}

pkg/loop/config_test.go

+50-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"strconv"
66
"strings"
77
"testing"
8+
"time"
89

910
"github.com/hashicorp/go-plugin"
1011
"github.com/stretchr/testify/assert"
@@ -16,10 +17,18 @@ import (
1617

1718
func TestEnvConfig_parse(t *testing.T) {
1819
cases := []struct {
19-
name string
20-
envVars map[string]string
21-
expectError bool
22-
expectedDatabaseURL string
20+
name string
21+
envVars map[string]string
22+
expectError bool
23+
24+
expectedDatabaseURL string
25+
expectedDatabaseIdleInTxSessionTimeout time.Duration
26+
expectedDatabaseLockTimeout time.Duration
27+
expectedDatabaseQueryTimeout time.Duration
28+
expectedDatabaseLogSQL bool
29+
expectedDatabaseMaxOpenConns int
30+
expectedDatabaseMaxIdleConns int
31+
2332
expectedPrometheusPort int
2433
expectedTracingEnabled bool
2534
expectedTracingCollectorTarget string
@@ -29,16 +38,31 @@ func TestEnvConfig_parse(t *testing.T) {
2938
{
3039
name: "All variables set correctly",
3140
envVars: map[string]string{
32-
envDatabaseURL: "postgres://user:password@localhost:5432/db",
41+
envDatabaseURL: "postgres://user:password@localhost:5432/db",
42+
envDatabaseIdleInTxSessionTimeout: "42s",
43+
envDatabaseLockTimeout: "8m",
44+
envDatabaseQueryTimeout: "7s",
45+
envDatabaseLogSQL: "true",
46+
envDatabaseMaxOpenConns: "9999",
47+
envDatabaseMaxIdleConns: "8080",
48+
3349
envPromPort: "8080",
3450
envTracingEnabled: "true",
3551
envTracingCollectorTarget: "some:target",
3652
envTracingSamplingRatio: "1.0",
3753
envTracingTLSCertPath: "internal/test/fixtures/client.pem",
3854
envTracingAttribute + "XYZ": "value",
3955
},
40-
expectError: false,
41-
expectedDatabaseURL: "postgres://user:password@localhost:5432/db",
56+
expectError: false,
57+
58+
expectedDatabaseURL: "postgres://user:password@localhost:5432/db",
59+
expectedDatabaseIdleInTxSessionTimeout: 42 * time.Second,
60+
expectedDatabaseLockTimeout: 8 * time.Minute,
61+
expectedDatabaseQueryTimeout: 7 * time.Second,
62+
expectedDatabaseLogSQL: true,
63+
expectedDatabaseMaxOpenConns: 9999,
64+
expectedDatabaseMaxIdleConns: 8080,
65+
4266
expectedPrometheusPort: 8080,
4367
expectedTracingEnabled: true,
4468
expectedTracingCollectorTarget: "some:target",
@@ -89,6 +113,25 @@ func TestEnvConfig_parse(t *testing.T) {
89113
if config.DatabaseURL.String() != tc.expectedDatabaseURL {
90114
t.Errorf("Expected Database URL %s, got %s", tc.expectedDatabaseURL, config.DatabaseURL)
91115
}
116+
if config.DatabaseIdleInTxSessionTimeout != tc.expectedDatabaseIdleInTxSessionTimeout {
117+
t.Errorf("Expected Database idle in tx session timeout %s, got %s", tc.expectedDatabaseIdleInTxSessionTimeout, config.DatabaseIdleInTxSessionTimeout)
118+
}
119+
if config.DatabaseLockTimeout != tc.expectedDatabaseLockTimeout {
120+
t.Errorf("Expected Database lock timeout %s, got %s", tc.expectedDatabaseLockTimeout, config.DatabaseLockTimeout)
121+
}
122+
if config.DatabaseQueryTimeout != tc.expectedDatabaseQueryTimeout {
123+
t.Errorf("Expected Database query timeout %s, got %s", tc.expectedDatabaseQueryTimeout, config.DatabaseQueryTimeout)
124+
}
125+
if config.DatabaseLogSQL != tc.expectedDatabaseLogSQL {
126+
t.Errorf("Expected Database log sql %t, got %t", tc.expectedDatabaseLogSQL, config.DatabaseLogSQL)
127+
}
128+
if config.DatabaseMaxOpenConns != tc.expectedDatabaseMaxOpenConns {
129+
t.Errorf("Expected Database max open conns %d, got %d", tc.expectedDatabaseMaxOpenConns, config.DatabaseMaxOpenConns)
130+
}
131+
if config.DatabaseMaxIdleConns != tc.expectedDatabaseMaxIdleConns {
132+
t.Errorf("Expected Database max idle conns %d, got %d", tc.expectedDatabaseMaxIdleConns, config.DatabaseMaxIdleConns)
133+
}
134+
92135
if config.PrometheusPort != tc.expectedPrometheusPort {
93136
t.Errorf("Expected Prometheus port %d, got %d", tc.expectedPrometheusPort, config.PrometheusPort)
94137
}

0 commit comments

Comments
 (0)