aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2024-12-19 09:42:17 +0000
committerdakkar <dakkar@thenautilus.net>2024-12-19 09:42:17 +0000
commitc940ac4f72e7e55ef1a7aa35cc0fc32684716977 (patch)
treedf46d71d6b0ea49a979f90fc43b6947617942b04
downloadgo-example-c940ac4f72e7e55ef1a7aa35cc0fc32684716977.tar.gz
go-example-c940ac4f72e7e55ef1a7aa35cc0fc32684716977.tar.bz2
go-example-c940ac4f72e7e55ef1a7aa35cc0fc32684716977.zip
minimal example
-rw-r--r--.gitignore5
-rw-r--r--.golangci.yml56
-rw-r--r--Makefile34
-rw-r--r--README.md27
-rw-r--r--cmd/main/main.go33
-rw-r--r--config/config.go126
-rw-r--r--example.development.json5
-rw-r--r--factory/factory.go33
-rw-r--r--go.mod29
-rw-r--r--go.sum68
-rw-r--r--logging/logging.go43
-rw-r--r--something/something.go23
12 files changed, 482 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ac21027
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*~
+*.sw?
+/*.tar.gz
+/go-example
+/cover.html
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..3fcf71e
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,56 @@
+---
+output:
+ sort-results: true
+
+run:
+ go: "1.23"
+
+linters-settings:
+ goimports:
+ local-prefixes: www.thenautilus.net/cgit
+
+ gci:
+ sections:
+ - standard
+ - default
+ - prefix(www.thenautilus.net/cgit)
+
+ misspell:
+ locale: "UK"
+
+ varnamelen:
+ ignore-names:
+ - ok
+ - w
+ - r
+
+ wsl:
+ # sometimes I really have to start a block with a comment!
+ allow-separated-leading-comment: true
+
+
+linters:
+ disable:
+ - ireturn # we should return concrete types, not interfaces, but I
+ # can't quite figure out how to do it...
+ - exhaustruct
+ - forbidigo
+ - depguard
+ - mnd
+ - nonamedreturns
+ presets:
+ - style
+ - bugs
+ - error
+ - format
+ - import
+ - module
+ - performance
+ - unused
+
+
+issues:
+ exclude:
+ - 'package should be `\w+_test`'
+ - 'package comment should not have leading space'
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1ee128f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,34 @@
+TARGET = go-example
+RUN_MODE ?= development
+GO ?= go
+
+$(TARGET): */*.go go.sum
+ $(GO) build -o $@ ./cmd/main/
+
+.PHONY: test
+test:
+ $(GO) test -cover -coverprofile=coverage.out -v ./...
+ $(GO) tool cover -html=coverage.out -o cover.html
+ rm coverage.out
+
+.PHONY: lint
+lint: fmt
+ ~/go/bin/golangci-lint run -v
+
+.PHONY: clean
+clean:
+ rm $(TARGET)
+
+.PHONY: fmt
+fmt:
+ ~/go/bin/goimports -local www.thenautilus.net/cgit -w .
+ ~/go/bin/gci write -s Standard -s Default -s 'Prefix(www.thenautilus.net/cgit)' .
+ ~/go/bin/gofumpt -l -w .
+
+.PHONY: run
+run: $(TARGET)
+ ./$(TARGET) --verbose --log-format=console $(ARGS)
+
+.PHONY: update
+update:
+ go get -u -t ./...
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..78052d6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,27 @@
+# A Go example
+
+You'll need `go` 1.23 at least.
+
+There's a [`Makefile`](Makefile), so you can do:
+
+ $ make clean
+ $ make test
+ $ make
+ $ make run
+
+If you run:
+
+ go install golang.org/x/tools/cmd/goimports@latest
+ go install github.com/daixiang0/gci@latest
+ go install mvdan.cc/gofumpt@latest
+
+then you can do `make fmt` to format all the source files.
+
+If you `go install
+github.com/golangci/golangci-lint/cmd/golangci-lint@latest`, you can
+also do `make lint` to get a linting / critique of all the source
+files (`lint` runs `fmt` first, so you need to have installed the
+packages above as well).
+
+Note that the `Makefile` is *for development*, it's not used on
+production machines.
diff --git a/cmd/main/main.go b/cmd/main/main.go
new file mode 100644
index 0000000..ac7f788
--- /dev/null
+++ b/cmd/main/main.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "www.thenautilus.net/cgit/go-example/config"
+ factorypkg "www.thenautilus.net/cgit/go-example/factory"
+ "www.thenautilus.net/cgit/go-example/logging"
+)
+
+func main() {
+ // this is the main binary, so the config file is in
+ // the same directory as the executable
+ config, err := config.GetMainConfig(".")
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+
+ log := logging.Logger(config.Logger)
+
+ log.Info().Object("config", &config).Msg("configuration")
+
+ factory := factorypkg.New(log, &config)
+
+ something := factory.Something()
+
+ err = something.DoSomething()
+ if err != nil {
+ log.Error().Err(err).Msg("Can't do the thing")
+ }
+}
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..3c93d53
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,126 @@
+package config
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path"
+ "strings"
+
+ "github.com/mitchellh/mapstructure"
+ "github.com/rs/zerolog"
+ "github.com/spf13/pflag"
+ "github.com/spf13/viper"
+)
+
+type LoggerConfig struct {
+ Verbose bool `mapstructure:"verbose"`
+ Format string `mapstructure:"format"`
+}
+
+func (c *LoggerConfig) MarshalZerologObject(e *zerolog.Event) {
+ e.
+ Bool("verbose", c.Verbose).
+ Str("format", c.Format)
+}
+
+type SomethingConfig struct {
+ Value int `mapstructure:"value"`
+}
+
+func (c *SomethingConfig) MarshalZerologObject(event *zerolog.Event) {
+ event.
+ Int("value", c.Value)
+}
+
+type MainConfig struct {
+ Something SomethingConfig `mapstructure:"something"`
+ Logger LoggerConfig `mapstructure:"logger"`
+
+ configFile string
+}
+
+func (c *MainConfig) MarshalZerologObject(event *zerolog.Event) {
+ event.
+ Str("config-file", c.configFile).
+ Object("logger", &c.Logger).
+ Object("something", &c.Something)
+}
+
+func addLoggerOptions() {
+ pflag.Bool("verbose", false, "log at debug level")
+ viper.BindPFlag("logger.verbose", pflag.Lookup("verbose")) //nolint:errcheck
+ pflag.String("log-format", "json", "logging format (json, console)")
+ viper.BindPFlag("logger.format", pflag.Lookup("log-format")) //nolint:errcheck
+}
+
+func addSomethingOptions() {
+ pflag.Int("something-value", 123, "value used to do something")
+ viper.BindPFlag("something.value", pflag.Lookup("something-value")) //nolint:errcheck
+ viper.BindEnv("something.value", "SOMETHING_VALUE") //nolint:errcheck
+}
+
+func addConfigFromFile(configRelPath string) error {
+ mode := os.Getenv("RUN_MODE")
+ if mode == "" {
+ mode = "development"
+ }
+
+ viper.SetConfigName("example." + mode)
+
+ myName, err := os.Executable()
+ if err == nil && !strings.HasPrefix(configRelPath, "/") {
+ myDir := path.Dir(myName)
+ viper.AddConfigPath(path.Join(myDir, configRelPath))
+ } else {
+ viper.AddConfigPath(configRelPath)
+ }
+
+ err = viper.ReadInConfig()
+ if err != nil {
+ var notFound viper.ConfigFileNotFoundError
+ if !errors.As(err, &notFound) {
+ return fmt.Errorf("failed to read config file at %s: %w", viper.ConfigFileUsed(), err)
+ }
+ }
+
+ return nil
+}
+
+func loadConfigFromFile(path string) (MainConfig, error) {
+ pathFromEnv := os.Getenv("EXAMPLE_CONFIG")
+ if pathFromEnv != "" {
+ path = pathFromEnv
+ }
+
+ err := addConfigFromFile(path)
+ if err != nil {
+ return MainConfig{}, err
+ }
+
+ var config MainConfig
+
+ err = viper.Unmarshal(&config, viper.DecodeHook(
+ mapstructure.ComposeDecodeHookFunc(
+ mapstructure.StringToTimeDurationHookFunc(),
+ mapstructure.StringToIPHookFunc(),
+ ),
+ ))
+ if err != nil {
+ return MainConfig{}, fmt.Errorf("failed to parse options: %w", err)
+ }
+
+ config.configFile = viper.ConfigFileUsed()
+
+ return config, nil
+}
+
+func GetMainConfig(path string) (MainConfig, error) {
+ addLoggerOptions()
+ addSomethingOptions()
+
+ pflag.Parse()
+ viper.BindPFlags(pflag.CommandLine) //nolint:errcheck
+
+ return loadConfigFromFile(path)
+}
diff --git a/example.development.json b/example.development.json
new file mode 100644
index 0000000..6c45101
--- /dev/null
+++ b/example.development.json
@@ -0,0 +1,5 @@
+{
+ "something": {
+ "value": 42
+ }
+}
diff --git a/factory/factory.go b/factory/factory.go
new file mode 100644
index 0000000..ae84911
--- /dev/null
+++ b/factory/factory.go
@@ -0,0 +1,33 @@
+package factory
+
+import (
+ "github.com/rs/zerolog"
+
+ "www.thenautilus.net/cgit/go-example/config"
+ "www.thenautilus.net/cgit/go-example/something"
+)
+
+type Factory struct {
+ something *something.Something
+
+ config *config.MainConfig
+ logger zerolog.Logger
+}
+
+func New(logger zerolog.Logger, config *config.MainConfig) Factory {
+ return Factory{
+ config: config,
+ logger: logger,
+ }
+}
+
+func (f *Factory) Something() *something.Something {
+ if f.something == nil {
+ something := something.New(
+ &f.config.Something,
+ )
+ f.something = &something
+ }
+
+ return f.something
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..e4fcf67
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,29 @@
+module www.thenautilus.net/cgit/go-example
+
+go 1.23
+
+require (
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/hashicorp/hcl v1.0.0 // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.2 // indirect
+ github.com/rs/zerolog v1.33.0 // indirect
+ github.com/sagikazarmark/locafero v0.4.0 // indirect
+ github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+ github.com/sourcegraph/conc v0.3.0 // indirect
+ github.com/spf13/afero v1.11.0 // indirect
+ github.com/spf13/cast v1.6.0 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ github.com/spf13/viper v1.19.0 // indirect
+ github.com/subosito/gotenv v1.6.0 // indirect
+ go.uber.org/atomic v1.9.0 // indirect
+ go.uber.org/multierr v1.9.0 // indirect
+ golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
+ golang.org/x/sys v0.18.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ gopkg.in/ini.v1 v1.67.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..02e8569
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,68 @@
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
+github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
+github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
+go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/logging/logging.go b/logging/logging.go
new file mode 100644
index 0000000..a24e13e
--- /dev/null
+++ b/logging/logging.go
@@ -0,0 +1,43 @@
+package logging
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "time"
+
+ "github.com/rs/zerolog"
+
+ "www.thenautilus.net/cgit/go-example/config"
+)
+
+// Logger returns a (optionally verbose) logger.
+func Logger(conf config.LoggerConfig) zerolog.Logger {
+ logLevel := zerolog.InfoLevel
+ if conf.Verbose {
+ logLevel = zerolog.DebugLevel
+ }
+
+ zerolog.TimestampFunc = func() time.Time {
+ return time.Now().UTC()
+ }
+
+ zerolog.InterfaceMarshalFunc = func(value interface{}) ([]byte, error) {
+ switch v := value.(type) {
+ case fmt.Stringer:
+ str := fmt.Sprintf("\"%s\"", v.String())
+
+ return []byte(str), nil
+ default:
+ return json.Marshal(value)
+ }
+ }
+
+ var w io.Writer = os.Stdout
+ if conf.Format == "console" {
+ w = zerolog.NewConsoleWriter()
+ }
+
+ return zerolog.New(w).Level(logLevel).With().Timestamp().Logger()
+}
diff --git a/something/something.go b/something/something.go
new file mode 100644
index 0000000..2516b2d
--- /dev/null
+++ b/something/something.go
@@ -0,0 +1,23 @@
+package something
+
+import (
+ "fmt"
+
+ "www.thenautilus.net/cgit/go-example/config"
+)
+
+type Something struct {
+ value int
+}
+
+func New(conf *config.SomethingConfig) Something {
+ return Something{
+ value: conf.Value,
+ }
+}
+
+func (s *Something) DoSomething() error {
+ fmt.Printf("the value is %d", s.value)
+
+ return nil
+}