logging and client, context utils
This commit is contained in:
parent
46fa5ea6bf
commit
9af155dbde
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
bin/*
|
||||
.env
|
||||
|
48
Makefile
48
Makefile
@ -1,39 +1,23 @@
|
||||
APP_NAME := eia-api-go
|
||||
SCHEMA_JSON := schema/eia-api-oapi.json
|
||||
SCHEMA_DIR := schema
|
||||
GENERATED_DIR := generated
|
||||
# Variables
|
||||
CLIENT_PKG := ./cmd/eia-client
|
||||
|
||||
# Default rule
|
||||
all: build
|
||||
.PHONY: all generate build install clean
|
||||
|
||||
# Retrieve and prepare the schema
|
||||
schema:
|
||||
mkdir -p $(SCHEMA_DIR)
|
||||
# if [ -f $(SCHEMA_JSON) ]; then rm -f $(SCHEMA_JSON); fi
|
||||
# curl -o $(SCHEMA_DIR)/eia-api-swagger.zip https://www.eia.gov/opendata/eia-api-swagger.zip
|
||||
# unzip -o $(SCHEMA_DIR)/eia-api-swagger.zip -d $(SCHEMA_DIR)
|
||||
# Default target
|
||||
all: generate build
|
||||
|
||||
# Generate the Go client using Swagger Codegen
|
||||
generate: schema
|
||||
mkdir -p $(GENERATED_DIR)
|
||||
docker run --rm \
|
||||
-v ${PWD}:/local \
|
||||
swaggerapi/swagger-codegen-cli-v3:latest generate \
|
||||
-i /local/$(SCHEMA_JSON) \
|
||||
-l go \
|
||||
-o /local/$(GENERATED_DIR)
|
||||
# Generate code
|
||||
generate:
|
||||
go generate ./...
|
||||
|
||||
# Build the application
|
||||
build:
|
||||
go build -o $(APP_NAME)
|
||||
# Build the client command binary
|
||||
build: generate
|
||||
go build -o bin/eia-client $(CLIENT_PKG)
|
||||
|
||||
# Install the application
|
||||
install:
|
||||
go install ./...
|
||||
# Install the client command binary
|
||||
install: generate
|
||||
go install $(CLIENT_PKG)
|
||||
|
||||
# Clean generated code
|
||||
# Clean up generated files and build artifacts
|
||||
clean:
|
||||
rm -rf $(GENERATED_DIR)
|
||||
rm -rf $(SCHEMA_DIR)
|
||||
|
||||
.PHONY: all schema generate build install clean
|
||||
rm -rf bin/eia-client
|
||||
|
@ -1,42 +0,0 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
eiaapi "gitea.libretechconsulting.com/50W/eia-api-go/api"
|
||||
)
|
||||
|
||||
var ListCmd = &cobra.Command{
|
||||
Use: "list <name>",
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Short: "List Available EIA Series",
|
||||
Run: runListCmd,
|
||||
}
|
||||
|
||||
func runListCmd(cmd *cobra.Command, _ []string) {
|
||||
client, err := eiaapi.NewClient("https://api.eia.gov")
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
resp, err := client.GetV2(cmd.Context())
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
response := make([]byte, 0)
|
||||
|
||||
_, err = resp.Body.Read(response)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", response)
|
||||
}
|
32
cmd/eia-client/cmd/list/list_series.go
Normal file
32
cmd/eia-client/cmd/list/list_series.go
Normal file
@ -0,0 +1,32 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/internal/util"
|
||||
)
|
||||
|
||||
var ListCmd = &cobra.Command{
|
||||
Use: "list <name>",
|
||||
Args: cobra.RangeArgs(0, 1),
|
||||
Short: "List Available EIA Series",
|
||||
PreRun: util.SetClient,
|
||||
Run: runListCmd,
|
||||
}
|
||||
|
||||
func runListCmd(cmd *cobra.Command, _ []string) {
|
||||
logger := util.Logger(cmd)
|
||||
client, err := util.Client(cmd)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
ctx, cncl := util.RequestCtx(cmd)
|
||||
defer cncl()
|
||||
resp, err := client.GetV2(ctx)
|
||||
if err != nil {
|
||||
logger.Err(err).Send()
|
||||
}
|
||||
|
||||
logger.Debug().Any("resp", resp).Send()
|
||||
}
|
@ -25,15 +25,32 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/cmd/client/cmd/list"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/cmd/list"
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/internal/util"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "eia-client",
|
||||
Short: "Useful utilities for EIA API v2",
|
||||
PersistentPreRun: PreRun,
|
||||
}
|
||||
|
||||
func PreRun(cmd *cobra.Command, _ []string) {
|
||||
// Set up logging
|
||||
console := zerolog.ConsoleWriter{
|
||||
Out: os.Stdout,
|
||||
TimeFormat: time.RFC1123,
|
||||
}
|
||||
logger := zerolog.New(console).With().
|
||||
Timestamp().Logger().Level(*util.GetLogLevel(cmd))
|
||||
|
||||
util.SetLogger(cmd, &logger)
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
@ -49,15 +66,21 @@ func Execute() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Here you will define your flags and configuration settings.
|
||||
// Cobra supports persistent flags, which, if defined here,
|
||||
// will be global for your application.
|
||||
// Enable PreRun for all commands
|
||||
cobra.EnableTraverseRunHooks = true
|
||||
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cmd.yaml)")
|
||||
// Handle command flags
|
||||
rootCmd.PersistentFlags().StringP(util.FLAG_LOG_LEVEL, "l", util.DefaultLogLevel.String(),
|
||||
"Log Level, or set "+util.ENV_LOG_LEVEL+" in environment")
|
||||
|
||||
// Cobra also supports local flags, which will only run
|
||||
// when this action is called directly.
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
rootCmd.PersistentFlags().StringP(util.FLAG_API_LOG_LEVEL, "L", util.DefAPILogLevel.String(),
|
||||
"Log Level for EIA API Middleware, or set "+util.ENV_API_LOG_LEVEL+" in environment")
|
||||
|
||||
rootCmd.PersistentFlags().StringP(util.FLAG_APIKEY,
|
||||
"a", "", "API Key, or set "+util.ENV_API+" in environment")
|
||||
|
||||
rootCmd.PersistentFlags().DurationP(util.FLAG_TMOUT, "t", util.DefRequestTimeout,
|
||||
"Request timeout, or set "+util.ENV_TMOUT+" in environment")
|
||||
|
||||
// Subcommands
|
||||
rootCmd.AddCommand(list.ListCmd)
|
28
cmd/eia-client/internal/util/util.go
Normal file
28
cmd/eia-client/internal/util/util.go
Normal file
@ -0,0 +1,28 @@
|
||||
package util
|
||||
|
||||
// These constants contain typed values
|
||||
// for safely setting and retrieving flags
|
||||
// from the cobra command
|
||||
const (
|
||||
FLAG_APIKEY = "apiKey"
|
||||
ENV_API = "EIA_API_KEY"
|
||||
|
||||
FLAG_TMOUT = "timeout"
|
||||
ENV_TMOUT = "EIA_API_TMOUT"
|
||||
|
||||
FLAG_API_LOG_LEVEL = "apiLogLevel"
|
||||
ENV_API_LOG_LEVEL = "EIA_API_LOG_LEVEL"
|
||||
|
||||
FLAG_LOG_LEVEL = "logLevel"
|
||||
ENV_LOG_LEVEL = "LOG_LEVEL"
|
||||
)
|
||||
|
||||
// Type for context data
|
||||
type eiaCtxField uint8
|
||||
|
||||
// These constants contain fields to safely set
|
||||
// or get fields from the command context
|
||||
const (
|
||||
CTX_EIA_CLIENT eiaCtxField = iota
|
||||
CTX_EIA_TMOUT
|
||||
)
|
67
cmd/eia-client/internal/util/util_api.go
Normal file
67
cmd/eia-client/internal/util/util_api.go
Normal file
@ -0,0 +1,67 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitea.libretechconsulting.com/50W/eia-api-go/pkg/eia"
|
||||
)
|
||||
|
||||
var (
|
||||
DefRequestTimeout = 5 * time.Second
|
||||
DefAPILogLevel = zerolog.DebugLevel
|
||||
)
|
||||
|
||||
func RequestCtx(cmd *cobra.Command) (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(cmd.Context(), GetRequestTmout(cmd))
|
||||
}
|
||||
|
||||
func GetRequestTmout(cmd *cobra.Command) time.Duration {
|
||||
tmout, ok := cmd.Context().Value(CTX_EIA_TMOUT).(time.Duration)
|
||||
if !ok || tmout == 0 {
|
||||
return DefRequestTimeout
|
||||
}
|
||||
return tmout
|
||||
}
|
||||
|
||||
func SetRequestTmout(cmd *cobra.Command, tmout time.Duration) {
|
||||
cmd.SetContext(context.WithValue(cmd.Context(),
|
||||
CTX_EIA_TMOUT, tmout))
|
||||
}
|
||||
|
||||
func Client(cmd *cobra.Command) (*eia.Client, error) {
|
||||
client, ok := cmd.Context().Value(CTX_EIA_CLIENT).(*eia.Client)
|
||||
if !ok {
|
||||
return nil, errors.New("command context lacks api client")
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func SetClient(cmd *cobra.Command, _ []string) {
|
||||
client, err := eia.NewClient(&eia.ClientOpts{
|
||||
Context: cmd.Context(),
|
||||
APIKey: GetAPIKey(cmd),
|
||||
Logger: Logger(cmd),
|
||||
LogLevel: GetAPILogLevel(cmd),
|
||||
})
|
||||
if err != nil {
|
||||
Logger(cmd).Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
cmd.SetContext(context.WithValue(cmd.Context(),
|
||||
CTX_EIA_CLIENT, client))
|
||||
}
|
||||
|
||||
func GetAPIKey(cmd *cobra.Command) string {
|
||||
if key := os.Getenv(ENV_API); key != "" {
|
||||
return key
|
||||
}
|
||||
|
||||
key, _ := cmd.Flags().GetString(FLAG_APIKEY)
|
||||
return key
|
||||
}
|
74
cmd/eia-client/internal/util/util_logging.go
Normal file
74
cmd/eia-client/internal/util/util_logging.go
Normal file
@ -0,0 +1,74 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var DefaultLogLevel = zerolog.InfoLevel
|
||||
|
||||
func Logger(cmd *cobra.Command) *zerolog.Logger {
|
||||
return zerolog.Ctx(cmd.Context())
|
||||
}
|
||||
|
||||
func SetLogger(cmd *cobra.Command, logger *zerolog.Logger) {
|
||||
cmd.SetContext(logger.WithContext(cmd.Context()))
|
||||
}
|
||||
|
||||
func GetLogLevel(cmd *cobra.Command) *zerolog.Level {
|
||||
var level zerolog.Level
|
||||
var err error
|
||||
if envLevel := os.Getenv(ENV_LOG_LEVEL); envLevel != "" {
|
||||
level, err = zerolog.ParseLevel(envLevel)
|
||||
if err != nil {
|
||||
Logger(cmd).Err(err).
|
||||
Str("envLogLevel", envLevel).
|
||||
Str("envVar", ENV_LOG_LEVEL).
|
||||
Str("defaultLevel", DefaultLogLevel.String()).
|
||||
Msg("Invalid log level in environment, using default")
|
||||
level = DefaultLogLevel
|
||||
}
|
||||
}
|
||||
|
||||
if flagLevel, err := cmd.Flags().GetString(FLAG_LOG_LEVEL); err == nil {
|
||||
level, err = zerolog.ParseLevel(flagLevel)
|
||||
if err != nil {
|
||||
Logger(cmd).Err(err).
|
||||
Str("flagLogLevel", flagLevel).
|
||||
Str("defaultLevel", DefaultLogLevel.String()).
|
||||
Msg("Invalid log level in command flag, using default")
|
||||
level = DefaultLogLevel
|
||||
}
|
||||
}
|
||||
return &level
|
||||
}
|
||||
|
||||
func GetAPILogLevel(cmd *cobra.Command) *zerolog.Level {
|
||||
var level zerolog.Level
|
||||
var err error
|
||||
if envLevel := os.Getenv(ENV_API_LOG_LEVEL); envLevel != "" {
|
||||
level, err = zerolog.ParseLevel(envLevel)
|
||||
if err != nil {
|
||||
Logger(cmd).Err(err).
|
||||
Str("envLogLevel", envLevel).
|
||||
Str("envVar", ENV_API_LOG_LEVEL).
|
||||
Str("defaultLevel", DefAPILogLevel.String()).
|
||||
Msg("Invalid API log level in environment, using default")
|
||||
level = DefAPILogLevel
|
||||
}
|
||||
}
|
||||
|
||||
if flagLevel, err := cmd.Flags().GetString(FLAG_API_LOG_LEVEL); err == nil {
|
||||
level, err = zerolog.ParseLevel(flagLevel)
|
||||
if err != nil {
|
||||
Logger(cmd).Err(err).
|
||||
Str("flagLogLevel", flagLevel).
|
||||
Str("defaultLevel", DefAPILogLevel.String()).
|
||||
Msg("Invalid API log level in command flag, using default")
|
||||
level = DefAPILogLevel
|
||||
}
|
||||
}
|
||||
return &level
|
||||
}
|
@ -21,7 +21,7 @@ THE SOFTWARE.
|
||||
*/
|
||||
package main
|
||||
|
||||
import "gitea.libretechconsulting.com/50W/eia-api-go/cmd/client/cmd"
|
||||
import "gitea.libretechconsulting.com/50W/eia-api-go/cmd/eia-client/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
5
go.mod
5
go.mod
@ -3,8 +3,10 @@ module gitea.libretechconsulting.com/50W/eia-api-go
|
||||
go 1.23.3
|
||||
|
||||
require (
|
||||
github.com/deepmap/oapi-codegen v1.16.3
|
||||
github.com/oapi-codegen/oapi-codegen/v2 v2.4.1
|
||||
github.com/oapi-codegen/runtime v1.1.1
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
)
|
||||
|
||||
@ -19,6 +21,8 @@ require (
|
||||
github.com/invopop/yaml v0.3.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect
|
||||
@ -26,6 +30,7 @@ require (
|
||||
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
golang.org/x/tools v0.27.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
17
go.sum
17
go.sum
@ -5,10 +5,13 @@ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvF
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deepmap/oapi-codegen v1.16.3 h1:GT9G86SbQtT1r8ZB+4Cybi9VGdu1P5ieNvNdEoCSbrA=
|
||||
github.com/deepmap/oapi-codegen v1.16.3/go.mod h1:JD6ErqeX0nYnhdciLc61Konj3NBASREMlkHOgHn8WAM=
|
||||
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
|
||||
github.com/dprotaso/go-yit v0.0.0-20240618133044-5a0af90af097 h1:f5nA5Ys8RXqFXtKc0XofVRiuwNTuJzPIwTmbjLz9vj8=
|
||||
github.com/dprotaso/go-yit v0.0.0-20240618133044-5a0af90af097/go.mod h1:FTAVyH6t+SlS97rv6EXRVuBDLkQqcIe/xQw9f4IFUI4=
|
||||
@ -24,6 +27,7 @@ github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
@ -60,6 +64,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
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/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
@ -84,10 +94,14 @@ github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
|
||||
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
@ -143,6 +157,9 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
87
pkg/eia/eia.go
Normal file
87
pkg/eia/eia.go
Normal file
@ -0,0 +1,87 @@
|
||||
package eia
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/securityprovider"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
eiaapi "gitea.libretechconsulting.com/50W/eia-api-go/api"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBaseURL = "https://api.eia.gov"
|
||||
defaultPingTimeout = 10 * time.Second
|
||||
defaultLogLevel = zerolog.DebugLevel
|
||||
)
|
||||
|
||||
// Simple wrapper around generated EIA API client
|
||||
// that embeds a client with a bearer auth interceptor
|
||||
// and optional logging middleware
|
||||
//
|
||||
// Performs a basic availability check against the API
|
||||
// when creating a new client, and exposes a Ping() method
|
||||
// for health / readiness probes
|
||||
type Client struct {
|
||||
ctx context.Context
|
||||
apiKey string
|
||||
healthCheckTimeout time.Duration
|
||||
*eiaapi.Client
|
||||
}
|
||||
|
||||
type ClientOpts struct {
|
||||
Context context.Context // Base context for requests
|
||||
APIKey string // API Key [EIA Opendata API v2](https://www.eia.gov/opendata/index.php)
|
||||
Logger *zerolog.Logger // Optional logger, if set is injected into logging middleware
|
||||
LogLevel *zerolog.Level // Optional log level, default is zerolog.DebugLevel
|
||||
BaseURL *url.URL // Optional, default is https://api.eia.gov
|
||||
HealthCheckTimeout *time.Duration // Timeout for Ping() function, default is 10s
|
||||
}
|
||||
|
||||
func NewClient(opts *ClientOpts) (*Client, error) {
|
||||
baseURL := defaultBaseURL
|
||||
if opts.BaseURL != nil {
|
||||
baseURL = opts.BaseURL.String()
|
||||
}
|
||||
|
||||
hcTimeout := defaultPingTimeout
|
||||
if opts.HealthCheckTimeout != nil && *opts.HealthCheckTimeout > time.Duration(0) {
|
||||
hcTimeout = *opts.HealthCheckTimeout
|
||||
}
|
||||
|
||||
middlewares := make([]eiaapi.ClientOption, 0, 2)
|
||||
|
||||
// Injects Authorization: Bearer <APIKey> header into
|
||||
// outbound API calls
|
||||
basicAuth, err := securityprovider.NewSecurityProviderBearerToken(opts.APIKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
middlewares = append(middlewares, eiaapi.WithRequestEditorFn(basicAuth.Intercept))
|
||||
|
||||
// Logging middleware, if logger is given
|
||||
if opts.Logger != nil {
|
||||
logLevel := defaultLogLevel
|
||||
if opts.LogLevel != nil {
|
||||
logLevel = *opts.LogLevel
|
||||
}
|
||||
|
||||
middlewares = append(middlewares,
|
||||
eiaapi.WithRequestEditorFn(newLoggingMiddleware(opts.Logger, logLevel)))
|
||||
}
|
||||
|
||||
client, err := eiaapi.NewClient(baseURL, slices.Clip(middlewares)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
apiKey: opts.APIKey,
|
||||
ctx: opts.Context,
|
||||
healthCheckTimeout: hcTimeout,
|
||||
Client: client,
|
||||
}, nil
|
||||
}
|
20
pkg/eia/eia_health.go
Normal file
20
pkg/eia/eia_health.go
Normal file
@ -0,0 +1,20 @@
|
||||
package eia
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (c *Client) Ping() error {
|
||||
ctx, cncl := context.WithTimeout(c.ctx, c.healthCheckTimeout)
|
||||
defer cncl()
|
||||
|
||||
resp, err := c.GetV2(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("non-200 response [%s] from eia api", resp.Status)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
24
pkg/eia/eia_logging.go
Normal file
24
pkg/eia/eia_logging.go
Normal file
@ -0,0 +1,24 @@
|
||||
package eia
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
eiaapi "gitea.libretechconsulting.com/50W/eia-api-go/api"
|
||||
)
|
||||
|
||||
func newLoggingMiddleware(logger *zerolog.Logger, level zerolog.Level) eiaapi.RequestEditorFn {
|
||||
return func(_ context.Context, req *http.Request) error {
|
||||
logger.WithLevel(level).
|
||||
Str("method", req.Method).
|
||||
Str("host", req.URL.Host).
|
||||
Str("path", req.URL.Path).
|
||||
Str("query", req.Form.Encode()).
|
||||
Time("timestamp", time.Now()).
|
||||
Send()
|
||||
return nil
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user