@@ -24,6 +24,7 @@ import (
2424
2525 "github.com/mxab/nacp/admissionctrl/remoteutil"
2626 "github.com/mxab/nacp/admissionctrl/types"
27+ "github.com/mxab/nacp/logutil"
2728 nacpOtel "github.com/mxab/nacp/otel"
2829
2930 "log/slog"
@@ -39,7 +40,6 @@ import (
3940 "github.com/notaryproject/notation-go/dir"
4041 "github.com/notaryproject/notation-go/verifier/truststore"
4142
42- "go.opentelemetry.io/contrib/bridges/otelslog"
4343 "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
4444)
4545
@@ -111,15 +111,15 @@ func resolveTokenAccessor(ctx context.Context, transport http.RoundTripper, noma
111111
112112 return & aclToken , nil
113113}
114- func NewProxyAsHandlerFunc (nomadAddress * url.URL , jobHandler * admissionctrl.JobHandler , appLogger * slog.Logger , transport http.RoundTripper ) http.HandlerFunc {
114+ func NewProxyAsHandlerFunc (nomadAddress * url.URL , jobHandler * admissionctrl.JobHandler , logger * slog.Logger , transport http.RoundTripper ) http.HandlerFunc {
115115
116- proxy := newProxyHandler (nomadAddress , jobHandler , appLogger , transport )
116+ proxy := newProxyHandler (nomadAddress , jobHandler , logger , transport )
117117 handlerFunc := http .HandlerFunc (proxy )
118118 handlerFunc = otelhttp .NewHandler (handlerFunc , "/" ).(http.HandlerFunc )
119119
120120 return handlerFunc
121121}
122- func newProxyHandler (nomadAddress * url.URL , jobHandler * admissionctrl.JobHandler , appLogger * slog.Logger , transport http.RoundTripper ) func (http.ResponseWriter , * http.Request ) {
122+ func newProxyHandler (nomadAddress * url.URL , jobHandler * admissionctrl.JobHandler , logger * slog.Logger , transport http.RoundTripper ) func (http.ResponseWriter , * http.Request ) {
123123
124124 proxy := httputil .NewSingleHostReverseProxy (nomadAddress )
125125
@@ -138,14 +138,14 @@ func newProxyHandler(nomadAddress *url.URL, jobHandler *admissionctrl.JobHandler
138138 var err error
139139
140140 if isRegister (resp .Request ) {
141- err = handRegisterResponse (resp , appLogger )
141+ err = handRegisterResponse (resp , logger )
142142 } else if isPlan (resp .Request ) {
143- err = handleJobPlanResponse (resp , appLogger )
143+ err = handleJobPlanResponse (resp , logger )
144144 } else if isValidate (resp .Request ) {
145- err = handleJobValdidateResponse (resp , appLogger )
145+ err = handleJobValdidateResponse (resp , logger )
146146 }
147147 if err != nil {
148- appLogger .ErrorContext (resp .Request .Context (), "Preparing response failed" , "error" , err )
148+ logger .ErrorContext (resp .Request .Context (), "Preparing response failed" , "error" , err )
149149 return err
150150 }
151151
@@ -166,34 +166,34 @@ func newProxyHandler(nomadAddress *url.URL, jobHandler *admissionctrl.JobHandler
166166 if jobHandler .ResolveToken () {
167167 tokenInfo , err := resolveTokenAccessor (ctx , transport , nomadAddress , token )
168168 if err != nil {
169- appLogger .ErrorContext (ctx , "Resolving token failed" , "error" , err )
169+ logger .ErrorContext (ctx , "Resolving token failed" , "error" , err )
170170 writeError (w , err )
171171 }
172172 if tokenInfo != nil {
173173 reqCtx .AccessorID = tokenInfo .AccessorID
174174 reqCtx .TokenInfo = tokenInfo
175175 }
176- appLogger .InfoContext (ctx , "Request received" , "path" , r .URL .Path , "method" , r .Method , "clientIP" , reqCtx .ClientIP , "accessorID" , reqCtx .AccessorID )
176+ logger .InfoContext (ctx , "Request received" , "path" , r .URL .Path , "method" , r .Method , "clientIP" , reqCtx .ClientIP , "accessorID" , reqCtx .AccessorID )
177177 } else {
178- appLogger .InfoContext (ctx , "Request received" , "path" , r .URL .Path , "method" , r .Method , "clientIP" , reqCtx .ClientIP )
178+ logger .InfoContext (ctx , "Request received" , "path" , r .URL .Path , "method" , r .Method , "clientIP" , reqCtx .ClientIP )
179179 }
180180
181181 ctx = context .WithValue (ctx , "request_context" , reqCtx )
182182 r = r .WithContext (ctx )
183183
184184 var err error
185185 if isRegister (r ) {
186- r , err = handleRegister (r , appLogger , jobHandler )
186+ r , err = handleRegister (r , logger , jobHandler )
187187
188188 } else if isPlan (r ) {
189- r , err = handlePlan (r , appLogger , jobHandler )
189+ r , err = handlePlan (r , logger , jobHandler )
190190
191191 } else if isValidate (r ) {
192- r , err = handleValidate (r , appLogger , jobHandler )
192+ r , err = handleValidate (r , logger , jobHandler )
193193
194194 }
195195 if err != nil {
196- appLogger .WarnContext (ctx , "Error applying admission controllers" , "error" , err )
196+ logger .WarnContext (ctx , "Error applying admission controllers" , "error" , err )
197197 writeError (w , err )
198198
199199 } else {
@@ -205,7 +205,7 @@ func newProxyHandler(nomadAddress *url.URL, jobHandler *admissionctrl.JobHandler
205205
206206}
207207
208- func handRegisterResponse (resp * http.Response , applogger * slog.Logger ) error {
208+ func handRegisterResponse (resp * http.Response , logger * slog.Logger ) error {
209209
210210 warnings , ok := resp .Request .Context ().Value (ctxWarnings ).([]error )
211211 if ! ok && len (warnings ) == 0 {
@@ -254,7 +254,7 @@ func checkIfGzipAndTransformReader(resp *http.Response, reader io.ReadCloser) (b
254254 }
255255 return isGzip , reader , nil
256256}
257- func handleJobPlanResponse (resp * http.Response , applogger * slog.Logger ) error {
257+ func handleJobPlanResponse (resp * http.Response , logger * slog.Logger ) error {
258258 warnings , ok := resp .Request .Context ().Value (ctxWarnings ).([]error )
259259 if ! ok && len (warnings ) == 0 {
260260 return nil
@@ -286,7 +286,7 @@ func handleJobPlanResponse(resp *http.Response, applogger *slog.Logger) error {
286286 }
287287 return nil
288288}
289- func handleJobValdidateResponse (resp * http.Response , appLogger * slog.Logger ) error {
289+ func handleJobValdidateResponse (resp * http.Response , logger * slog.Logger ) error {
290290
291291 ctx := resp .Request .Context ()
292292 validationErr , okErr := ctx .Value (ctxValidationError ).(error )
@@ -528,20 +528,26 @@ func isValidate(r *http.Request) bool {
528528 return (r .Method == "PUT" || r .Method == "POST" ) && r .URL .Path == "/v1/validate/job"
529529}
530530
531+ func buildSlogHandler (json bool , level slog.Level ) slog.Handler {
532+ opts := & slog.HandlerOptions {
533+ Level : level ,
534+ }
535+ if json {
536+ return slog .NewJSONHandler (os .Stdout , opts )
537+ }
538+ return slog .NewTextHandler (os .Stdout , opts )
539+ }
540+
531541// https://www.codedodle.com/go-reverse-proxy-example.html
532542// https://joshsoftware.wordpress.com/2021/05/25/simple-and-powerful-reverseproxy-in-go/
543+
533544func main () {
534545
535546 configPtr := flag .String ("config" , "" , "point to a nacp config file" )
536547 bootstrapLoggerHandlerPtr := flag .Bool ("bootstrap-json-logger" , false , "use json for initial logging until config is loaded" )
537548 flag .Parse ()
538- var bootstrapLogger * slog.Logger
539- if * bootstrapLoggerHandlerPtr {
540- bootstrapLogger = slog .New (slog .NewJSONHandler (os .Stdout , nil ))
541- } else {
542- bootstrapLogger = slog .New (slog .NewTextHandler (os .Stdout , nil ))
543- }
544- slog .SetDefault (bootstrapLogger )
549+
550+ slog .SetDefault (slog .New (buildSlogHandler (* bootstrapLoggerHandlerPtr , slog .LevelInfo )))
545551
546552 c , err := buildConfig (* configPtr )
547553 if err != nil {
@@ -561,37 +567,27 @@ func run(c *config.Config) (err error) {
561567 ctx , stop := signal .NotifyContext (context .Background (), os .Interrupt )
562568 defer stop ()
563569
564- loggerFactory , err := buildLoggerFactory ( c )
565- if err != nil {
566- return fmt . Errorf ( "failed to build logger factory: %w" , err )
567- }
570+ rootFactory , leveler := logutil . NewLoggerFactoryFromConfig ( c . Telemetry . Logging )
571+
572+ appLogger := rootFactory . GetLogger ( "nacp" )
573+ slog . SetDefault ( appLogger )
568574
569- logger := loggerFactory ("nacp" )
570- slog .SetDefault (logger )
571- appLogger := logger
572- setupOtel := c .Telemetry .Logging .IsOtel () || c .Telemetry .Metrics .Enabled || c .Telemetry .Tracing .Enabled
575+ setupOtel := * c .Telemetry .Logging .OtelLogging .Enabled || c .Telemetry .Metrics .Enabled || c .Telemetry .Tracing .Enabled
573576 if setupOtel {
574577 // Set up OpenTelemetry.
575- otelShutdown , err := nacpOtel .SetupOTelSDK (ctx , c .Telemetry .Logging .IsOtel () , c .Telemetry .Metrics .Enabled , c .Telemetry .Tracing .Enabled , version )
578+ otelShutdown , err := nacpOtel .SetupOTelSDK (ctx , * c .Telemetry .Logging .OtelLogging . Enabled , c .Telemetry .Metrics .Enabled , c .Telemetry .Tracing .Enabled , version , leveler . GetSeverietier () )
576579 if err != nil {
577580 return fmt .Errorf ("failed to setup OpenTelemetry: %w" , err )
578581 }
579582 // Handle shutdown properly so nothing leaks.
580583 // https://opentelemetry.io/docs/languages/go/getting-started/
581584 defer func () {
582585 err = errors .Join (err , otelShutdown (context .Background ()))
583-
584586 }()
585587
586588 }
587589
588- level := slog .Level (0 )
589- if err := level .UnmarshalText ([]byte (c .Telemetry .Logging .Level )); err != nil {
590- return fmt .Errorf ("failed to parse log level: %w" , err )
591- }
592- slog .SetLogLoggerLevel (level )
593-
594- server , err := buildServer (c , loggerFactory )
590+ server , err := buildServer (c , rootFactory )
595591
596592 if err != nil {
597593 return fmt .Errorf ("failed to build server: %w" , err )
@@ -627,34 +623,7 @@ func run(c *config.Config) (err error) {
627623
628624}
629625
630- func buildLoggerFactory (c * config.Config ) (lf loggerFactory , err error ) {
631- if c .Telemetry .Logging .IsSlog () {
632- if c .Telemetry .Logging .SlogLogging .Handler == "json" {
633- lf = func (_ string ) * slog.Logger {
634- return slog .New (slog .NewJSONHandler (os .Stdout , nil ))
635- }
636-
637- } else if c .Telemetry .Logging .SlogLogging .Handler == "text" {
638- lf = func (_ string ) * slog.Logger {
639- return slog .New (slog .NewTextHandler (os .Stdout , nil ))
640- }
641-
642- } else {
643- return nil , fmt .Errorf ("invalid slog logging handler, only json and text are supported" )
644- }
645-
646- } else if c .Telemetry .Logging .IsOtel () {
647- lf = func (name string ) * slog.Logger {
648- return otelslog .NewLogger (name )
649- }
650-
651- } else {
652- return nil , fmt .Errorf ("invalid logging type, only slog and otel are supported" )
653- }
654- return
655- }
656-
657- func buildServer (c * config.Config , loggerFactory loggerFactory ) (* http.Server , error ) {
626+ func buildServer (c * config.Config , loggerFactory * logutil.LoggerFactory ) (* http.Server , error ) {
658627 backend , err := url .Parse (c .Nomad .Address )
659628 if err != nil {
660629 return nil , fmt .Errorf ("failed to parse nomad address: %w" , err )
@@ -696,11 +665,11 @@ func buildServer(c *config.Config, loggerFactory loggerFactory) (*http.Server, e
696665
697666 jobMutators ,
698667 jobValidators ,
699- loggerFactory ("handler" ),
668+ loggerFactory . GetLogger ("handler" ),
700669 resolveToken ,
701670 )
702671
703- handlerFunc := NewProxyAsHandlerFunc (backend , jobHandler , loggerFactory ("proxy-handler" ), instrumentedProxyTransport )
672+ handlerFunc := NewProxyAsHandlerFunc (backend , jobHandler , loggerFactory . GetLogger ("proxy-handler" ), instrumentedProxyTransport )
704673
705674 bind := fmt .Sprintf ("%s:%d" , c .Bind , c .Port )
706675 var tlsConfig * tls.Config
@@ -760,7 +729,7 @@ func createTlsConfig(caFile string, noClientCert bool) (*tls.Config, error) {
760729 return tlsConfig , nil
761730}
762731
763- func createMutators (c * config.Config , loggerFactory loggerFactory ) ([]admissionctrl.JobMutator , bool , error ) {
732+ func createMutators (c * config.Config , loggerFactory * logutil. LoggerFactory ) ([]admissionctrl.JobMutator , bool , error ) {
764733 var jobMutators []admissionctrl.JobMutator
765734 var resolveToken bool
766735 for _ , m := range c .Mutators {
@@ -769,18 +738,18 @@ func createMutators(c *config.Config, loggerFactory loggerFactory) ([]admissionc
769738 }
770739 switch m .Type {
771740 case "opa_json_patch" :
772- notationVerifier , err := buildVerifierIfEnabled (m .OpaRule .Notation , loggerFactory ("notation_verifier" ))
741+ notationVerifier , err := buildVerifierIfEnabled (m .OpaRule .Notation , loggerFactory . GetLogger ("notation_verifier" ))
773742 if err != nil {
774743 return nil , resolveToken , err
775744 }
776- mutator , err := mutator .NewOpaJsonPatchMutator (m .Name , m .OpaRule .Filename , m .OpaRule .Query , loggerFactory ("opa_mutator" ), notationVerifier )
745+ mutator , err := mutator .NewOpaJsonPatchMutator (m .Name , m .OpaRule .Filename , m .OpaRule .Query , loggerFactory . GetLogger ("opa_mutator" ), notationVerifier )
777746 if err != nil {
778747 return nil , resolveToken , err
779748 }
780749 jobMutators = append (jobMutators , mutator )
781750
782751 case "json_patch_webhook" :
783- mutator , err := mutator .NewJsonPatchWebhookMutator (m .Name , m .Webhook .Endpoint , m .Webhook .Method , loggerFactory ("json_patch_webhook_mutator" ))
752+ mutator , err := mutator .NewJsonPatchWebhookMutator (m .Name , m .Webhook .Endpoint , m .Webhook .Method , loggerFactory . GetLogger ("json_patch_webhook_mutator" ))
784753 if err != nil {
785754 return nil , resolveToken , err
786755 }
@@ -793,7 +762,7 @@ func createMutators(c *config.Config, loggerFactory loggerFactory) ([]admissionc
793762 }
794763 return jobMutators , resolveToken , nil
795764}
796- func createValidators (c * config.Config , loggerFactory loggerFactory ) ([]admissionctrl.JobValidator , bool , error ) {
765+ func createValidators (c * config.Config , loggerFactory * logutil. LoggerFactory ) ([]admissionctrl.JobValidator , bool , error ) {
797766 var jobValidators []admissionctrl.JobValidator
798767 var resolveToken bool
799768 for _ , v := range c .Validators {
@@ -802,28 +771,28 @@ func createValidators(c *config.Config, loggerFactory loggerFactory) ([]admissio
802771 }
803772 switch v .Type {
804773 case "opa" :
805- notationVerifier , err := buildVerifierIfEnabled (v .Notation , loggerFactory ("notation_verifier" ))
774+ notationVerifier , err := buildVerifierIfEnabled (v .Notation , loggerFactory . GetLogger ("notation_verifier" ))
806775 if err != nil {
807776 return nil , resolveToken , err
808777 }
809- opaValidator , err := validator .NewOpaValidator (v .Name , v .OpaRule .Filename , v .OpaRule .Query , loggerFactory ("opa_validator" ), notationVerifier )
778+ opaValidator , err := validator .NewOpaValidator (v .Name , v .OpaRule .Filename , v .OpaRule .Query , loggerFactory . GetLogger ("opa_validator" ), notationVerifier )
810779 if err != nil {
811780 return nil , resolveToken , err
812781 }
813782 jobValidators = append (jobValidators , opaValidator )
814783
815784 case "webhook" :
816- validator , err := validator .NewWebhookValidator (v .Name , v .Webhook .Endpoint , v .Webhook .Method , loggerFactory ("webhook_validator" ))
785+ validator , err := validator .NewWebhookValidator (v .Name , v .Webhook .Endpoint , v .Webhook .Method , loggerFactory . GetLogger ("webhook_validator" ))
817786 if err != nil {
818787 return nil , resolveToken , err
819788 }
820789 jobValidators = append (jobValidators , validator )
821790 case "notation" :
822- notationVerifier , err := buildVerifier (v .Notation , loggerFactory ("notation_verifier" ))
791+ notationVerifier , err := buildVerifier (v .Notation , loggerFactory . GetLogger ("notation_verifier" ))
823792 if err != nil {
824793 return nil , resolveToken , err
825794 }
826- validator := validator .NewNotationValidator (loggerFactory ("notation_validator" ), v .Name , notationVerifier )
795+ validator := validator .NewNotationValidator (loggerFactory . GetLogger ("notation_validator" ), v .Name , notationVerifier )
827796
828797 jobValidators = append (jobValidators , validator )
829798
0 commit comments