package main
import (
"fmt""github.com/yoshikipom/go/config/internal/config"
)
func main() {
// call only once
err := config.Initialize("./config/config.yml")
if err != nil {
panic(err)
}
// you can get config anywhere
c := config.GetConfig()
fmt.Printf("%+v", c)
}
実行例
# config.ymlの値が読めている
yoshiki@yoshiki-mbp:go/config ‹main*›$ go run "/Users/yoshiki/work/study/go/config/main.go"
&{Port:8080 Key:value}%
# 環境変数で渡した"new_value"が読み込めている。(key= でなく KEY= の理由は後述。)
yoshiki@yoshiki-mbp:go/config ‹main*›$ KEY=new_value go run "/Users/yoshiki/work/study/go/config/main.go"
&{Port:8080 Key:new_value}%
config.goの実装
package config
import (
"github.com/spf13/viper"
)
var config *MyConfig
type MyConfig struct {
Port int`mapstructure:"port"`
Key string`mapstructure:"key"`
}
func Initialize(fileName string) error {
viper.SetConfigFile(fileName)
if err := viper.ReadInConfig(); err != nil {
return err
}
viper.AutomaticEnv()
c := &MyConfig{}
if err := viper.Unmarshal(c); err != nil {
return err
}
config = c
returnnil
}
func GetConfig() *MyConfig {
if config == nil {
panic("config is not initialized.")
}
return config
}
@SpringBootApplication
@Slf4j
@RequiredArgsConstructor
@ConfigurationPropertiesScan
public class PluginSampleApplication implements CommandLineRunner {
private final CoreExecutor coreExecutor;
public static void main(String[] args) {
SpringApplication.run(PluginSampleApplication.class, args);
System.exit(0);
}
@Override
public void run(String... args) throws Exception {
log.info("===== run app for 'groupA' =====");
coreExecutor.execute(new CoreExecutorInput("groupA"));
log.info("===== run app for 'groupB' =====");
coreExecutor.execute(new CoreExecutorInput("groupB"));
log.info("===== run app for 'groupC (no config)' =====");
coreExecutor.execute(new CoreExecutorInput("groupC"));
}
}
アプリケーションログ
===== run app for 'groupA' =====
process before plugins is running
FooPlugin is running!
process after plugins is running
===== run app for 'groupB' =====
process before plugins is running
BarPlugin is running!
FooPlugin is running!
process after plugins is running
===== run app for 'groupC (no config)' =====
process before plugins is running
process after plugins is running
@Component("barPlugin")
@Slf4j
public class BarPlugin implements Plugin {
@Override
public PluginOutput execute(PluginInput pluginInput) {
log.info("BarPlugin is running!");
return new PluginOutput();
}
}
@RequiredArgsConstructor
@Component
@Slf4j
public class PluginExecutor {
private final PluginConfig pluginConfig;
private final Map<String, Plugin> pluginMap;
public void execute(String pluginGroupName) {
// load config
List<String> pluginNames = pluginConfig.pluginMap()
.getOrDefault(pluginGroupName, null);
// if no plugin config, return
if (pluginNames == null) {
return;
}
// execute plugins one by one
for (var pluginName : pluginNames) {
Plugin plugin = pluginMap.get(pluginName);
PluginInput pluginInput = new PluginInput(); // you can add any input to this class
PluginOutput pluginOutput = plugin.execute(pluginInput);
// consume pluginOutput if necessary
}
}
}
FROM golang:1.19 as builder
RUN apt-get update && apt-get install ruby vim-common -y
RUN apt-get install flex bison -y
RUN wget http://www.tcpdump.org/release/libpcap-1.10.0.tar.gz && tar xzf libpcap-1.10.0.tar.gz && cd libpcap-1.10.0 && ./configure && make install
WORKDIR /go/src/github.com/buger/goreplay/
RUN wget https://github.com/buger/goreplay/archive/refs/tags/v2.0.0-rc2.tar.gz -O gor.tar.gz && tar xzf gor.tar.gz -C . --strip=1
RUN go mod vendor
RUN go build -mod=vendor -tags netgo -o gor -ldflags "-extldflags \"-static\""
FROM alpine:3.17
RUN apk add bash
RUN apk add --no-cache ca-certificates openssl
COPY --from=builder /go/src/github.com/buger/goreplay/gor /
ENTRYPOINT ["./gor"]
build & run
# build
$ docker build --tag goreplay:2.0.0 .
# run
$ docker run --rm -it goreplay:2.0.0 -h
Gor is a simple http traffic replication tool written in Go. Its main goal is to replay traffic from production servers to staging and dev environments.
Makefileはbuild用のDockerコンテナ内でビルドする作りになっていたが、docker in dockerをしたくなかったのでマルチステージビルドを使って書いてみた。golangイメージでビルドして、alpineイメージで実行。goのプログラムは実行ファイルだけあれば実行できるのですごい。