Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for JSON logging. #1511

Merged
merged 1 commit into from
Sep 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/contour/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext)
serve.Flag("envoy-service-https-port", "Kubernetes Service port for HTTPS requests").IntVar(&ctx.httpsPort)
serve.Flag("use-proxy-protocol", "Use PROXY protocol for all listeners").BoolVar(&ctx.useProxyProto)

serve.Flag("accesslog-format", "Format for Envoy access logs").StringVar(&ctx.AccessLogFormat)
serve.Flag("disable-leader-election", "Disable leader election mechanism").BoolVar(&ctx.DisableLeaderElection)
return serve, ctx
}
Expand Down Expand Up @@ -141,6 +142,8 @@ func doServe(log logrus.FieldLogger, ctx *serveContext) error {
HTTPSAddress: ctx.httpsAddr,
HTTPSPort: ctx.httpsPort,
HTTPSAccessLog: ctx.httpsAccessLog,
AccessLogType: ctx.AccessLogFormat,
AccessLogFields: ctx.AccessLogFields,
MinimumProtocolVersion: dag.MinProtoVersion(ctx.TLSConfig.MinimumProtocolVersion),
},
ListenerCache: contour.NewListenerCache(ctx.statsAddr, ctx.statsPort),
Expand Down
34 changes: 34 additions & 0 deletions cmd/contour/servecontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ type serveContext struct {
httpsPort int
httpsAccessLog string

// Envoy's access logging format options

// AccessLogFormat sets the global access log format.
// Valid options are 'clf' or 'json'
AccessLogFormat string `yaml:"accesslog-format"`

// AccessLogFields sets the fields that JSON logging will
// output when AccessLogFormat is json.
AccessLogFields []string `yaml:"json-fields"`

// PermitInsecureGRPC disables TLS on Contour's gRPC listener.
PermitInsecureGRPC bool `yaml:"-"`

Expand Down Expand Up @@ -109,6 +119,30 @@ func newServeContext() *serveContext {
PermitInsecureGRPC: false,
DisablePermitInsecure: false,
DisableLeaderElection: false,
AccessLogFormat: "clf",
AccessLogFields: []string{
"@timestamp",
"authority",
"bytes_received",
"bytes_sent",
"downstream_local_address",
"downstream_remote_address",
"duration",
"method",
"path",
"protocol",
"request_id",
"requested_server_name",
"response_code",
"response_flags",
"uber_trace_id",
"upstream_cluster",
"upstream_host",
"upstream_local_address",
"upstream_service_time",
"user_agent",
"x_forwarded_for",
},
LeaderElectionConfig: LeaderElectionConfig{
LeaseDuration: time.Second * 15,
RenewDeadline: time.Second * 10,
Expand Down
56 changes: 53 additions & 3 deletions internal/contour/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth"
envoy_api_v2_listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
envoy_api_v2_accesslog "github.com/envoyproxy/go-control-plane/envoy/config/filter/accesslog/v2"

v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
"github.com/envoyproxy/go-control-plane/pkg/cache"
Expand All @@ -36,6 +37,7 @@ const (
DEFAULT_HTTPS_ACCESS_LOG = "/dev/stdout"
DEFAULT_HTTPS_LISTENER_ADDRESS = DEFAULT_HTTP_LISTENER_ADDRESS
DEFAULT_HTTPS_LISTENER_PORT = 8443
DEFAULT_ACCESS_LOG_TYPE = "clf"
)

// ListenerVisitorConfig holds configuration parameters for visitListeners.
Expand Down Expand Up @@ -71,6 +73,16 @@ type ListenerVisitorConfig struct {

// MinimumProtocolVersion defines the min tls protocol version to be used
MinimumProtocolVersion envoy_api_v2_auth.TlsParameters_TlsProtocol

// AccessLogType defines if Envoy logs should be output as CLF or JSON.
// Valid values: 'clf', 'json'
// If not set, defaults to 'clf'
AccessLogType string

// AccessLogFields sets the fields that should be shown in JSON logs.
// Valid entries are the keys from internal/envoy/accesslog.go:jsonheaders
// Defaults to a particular set of fields.
AccessLogFields []string
}

// httpAddress returns the port for the HTTP (non TLS)
Expand Down Expand Up @@ -127,6 +139,42 @@ func (lvc *ListenerVisitorConfig) httpsAccessLog() string {
return DEFAULT_HTTPS_ACCESS_LOG
}

// accesslogType returns the access log type that should be configured
// across all listener types or DEFAULT_ACCESS_LOG_TYPE if not configured.
func (lvc *ListenerVisitorConfig) accesslogType() string {
if lvc.AccessLogType != "" {
return lvc.AccessLogType
}
return DEFAULT_ACCESS_LOG_TYPE
}

// accesslogFields returns the access log fields that should be configured
// for Envoy, or a default set if not configured.
func (lvc *ListenerVisitorConfig) accesslogFields() []string {
if lvc.AccessLogFields != nil {
return lvc.AccessLogFields
}
return envoy.DefaultFields
}

func (lvc *ListenerVisitorConfig) newInsecureAccessLog() []*envoy_api_v2_accesslog.AccessLog {
switch lvc.accesslogType() {
case "json":
return envoy.FileAccessLogJSON(lvc.httpAccessLog(), lvc.accesslogFields())
default:
return envoy.FileAccessLog(lvc.httpAccessLog())
}
}

func (lvc *ListenerVisitorConfig) newSecureAccessLog() []*envoy_api_v2_accesslog.AccessLog {
switch lvc.accesslogType() {
case "json":
youngnick marked this conversation as resolved.
Show resolved Hide resolved
return envoy.FileAccessLogJSON(lvc.httpsAccessLog(), lvc.accesslogFields())
default:
return envoy.FileAccessLog(lvc.httpsAccessLog())
}
}

// minProtocolVersion returns the requested minimum TLS protocol
// version or envoy_api_v2_auth.TlsParameters_TLSv1_1 if not configured {
func (lvc *ListenerVisitorConfig) minProtoVersion() envoy_api_v2_auth.TlsParameters_TlsProtocol {
Expand Down Expand Up @@ -178,6 +226,8 @@ func (c *ListenerCache) Contents() []proto.Message {
return values
}

// Query returns the proto.Messages in the ListenerCache that match
// a slice of strings
func (c *ListenerCache) Query(names []string) []proto.Message {
c.mu.Lock()
defer c.mu.Unlock()
Expand Down Expand Up @@ -237,7 +287,7 @@ func visitListeners(root dag.Vertex, lvc *ListenerVisitorConfig) map[string]*v2.
ENVOY_HTTP_LISTENER,
lvc.httpAddress(), lvc.httpPort(),
proxyProtocol(lvc.UseProxyProto),
envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, lvc.httpAccessLog()),
envoy.HTTPConnectionManager(ENVOY_HTTP_LISTENER, lvc.newInsecureAccessLog()),
)

}
Expand Down Expand Up @@ -289,12 +339,12 @@ func (v *listenerVisitor) visit(vertex dag.Vertex) {
v.http = true
case *dag.SecureVirtualHost:
filters := envoy.Filters(
envoy.HTTPConnectionManager(ENVOY_HTTPS_LISTENER, v.httpsAccessLog()),
envoy.HTTPConnectionManager(ENVOY_HTTPS_LISTENER, v.ListenerVisitorConfig.newSecureAccessLog()),
)
alpnProtos := []string{"h2", "http/1.1"}
if vh.TCPProxy != nil {
filters = envoy.Filters(
envoy.TCPProxy(ENVOY_HTTPS_LISTENER, vh.TCPProxy, v.httpsAccessLog()),
envoy.TCPProxy(ENVOY_HTTPS_LISTENER, vh.TCPProxy, v.ListenerVisitorConfig.newSecureAccessLog()),
)
alpnProtos = nil // do not offer ALPN
}
Expand Down
Loading