mirror of https://github.com/status-im/consul.git
feat: add access logging API to proxy defaults (#15780)
This commit is contained in:
parent
04bf24c8c1
commit
233dbcb67f
|
@ -1,6 +1,7 @@
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
@ -341,6 +342,7 @@ type ProxyConfigEntry struct {
|
||||||
TransparentProxy TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
TransparentProxy TransparentProxyConfig `json:",omitempty" alias:"transparent_proxy"`
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||||
Expose ExposeConfig `json:",omitempty"`
|
Expose ExposeConfig `json:",omitempty"`
|
||||||
|
AccessLogs AccessLogsConfig `json:",omitempty" alias:"access_logs"`
|
||||||
|
|
||||||
Meta map[string]string `json:",omitempty"`
|
Meta map[string]string `json:",omitempty"`
|
||||||
acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
acl.EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
|
||||||
|
@ -395,6 +397,32 @@ func (e *ProxyConfigEntry) Validate() error {
|
||||||
return fmt.Errorf("invalid name (%q), only %q is supported", e.Name, ProxyConfigGlobal)
|
return fmt.Errorf("invalid name (%q), only %q is supported", e.Name, ProxyConfigGlobal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch e.AccessLogs.Type {
|
||||||
|
case "", StdErrLogSinkType, StdOutLogSinkType:
|
||||||
|
// OK
|
||||||
|
case FileLogSinkType:
|
||||||
|
if e.AccessLogs.Path == "" {
|
||||||
|
return errors.New("path must be specified when using file type access logs")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid access log type: %s", e.AccessLogs.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.AccessLogs.JSONFormat != "" && e.AccessLogs.TextFormat != "" {
|
||||||
|
return errors.New("cannot specify both access log JSONFormat and TextFormat")
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.AccessLogs.Type != FileLogSinkType && e.AccessLogs.Path != "" {
|
||||||
|
return errors.New("path is only valid for file type access logs")
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.AccessLogs.JSONFormat != "" {
|
||||||
|
msg := json.RawMessage{}
|
||||||
|
if err := json.Unmarshal([]byte(e.AccessLogs.JSONFormat), &msg); err != nil {
|
||||||
|
return fmt.Errorf("invalid access log json for JSON format: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := validateConfigEntryMeta(e.Meta); err != nil {
|
if err := validateConfigEntryMeta(e.Meta); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3030,6 +3030,57 @@ func TestProxyConfigEntry(t *testing.T) {
|
||||||
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
|
EnterpriseMeta: *acl.DefaultEnterpriseMeta(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"proxy config has invalid access log type": {
|
||||||
|
entry: &ProxyConfigEntry{
|
||||||
|
Name: "global",
|
||||||
|
AccessLogs: AccessLogsConfig{
|
||||||
|
Enabled: true,
|
||||||
|
Type: "stdin",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "invalid access log type: stdin",
|
||||||
|
},
|
||||||
|
"proxy config has invalid access log config - both text and json formats": {
|
||||||
|
entry: &ProxyConfigEntry{
|
||||||
|
Name: "global",
|
||||||
|
AccessLogs: AccessLogsConfig{
|
||||||
|
Enabled: true,
|
||||||
|
JSONFormat: "[%START_TIME%]",
|
||||||
|
TextFormat: "{\"start_time\": \"[%START_TIME%]\"}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "cannot specify both access log JSONFormat and TextFormat",
|
||||||
|
},
|
||||||
|
"proxy config has invalid access log config - file path with wrong type": {
|
||||||
|
entry: &ProxyConfigEntry{
|
||||||
|
Name: "global",
|
||||||
|
AccessLogs: AccessLogsConfig{
|
||||||
|
Enabled: true,
|
||||||
|
Path: "/tmp/logs.txt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "path is only valid for file type access logs",
|
||||||
|
},
|
||||||
|
"proxy config has invalid access log config - no file path specified": {
|
||||||
|
entry: &ProxyConfigEntry{
|
||||||
|
Name: "global",
|
||||||
|
AccessLogs: AccessLogsConfig{
|
||||||
|
Enabled: true,
|
||||||
|
Type: FileLogSinkType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "path must be specified when using file type access logs",
|
||||||
|
},
|
||||||
|
"proxy config has invalid access log JSON format": {
|
||||||
|
entry: &ProxyConfigEntry{
|
||||||
|
Name: "global",
|
||||||
|
AccessLogs: AccessLogsConfig{
|
||||||
|
Enabled: true,
|
||||||
|
JSONFormat: "{\"start_time\": \"[%START_TIME%]\"", // Missing trailing brace
|
||||||
|
},
|
||||||
|
},
|
||||||
|
validateErr: "invalid access log json for JSON format",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testConfigEntryNormalizeAndValidate(t, cases)
|
testConfigEntryNormalizeAndValidate(t, cases)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,14 @@ const (
|
||||||
MeshGatewayModeRemote MeshGatewayMode = "remote"
|
MeshGatewayModeRemote MeshGatewayMode = "remote"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type LogSinkType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FileLogSinkType LogSinkType = "file"
|
||||||
|
StdErrLogSinkType LogSinkType = "stderr"
|
||||||
|
StdOutLogSinkType LogSinkType = "stdout"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TODO (freddy) Should we have a TopologySourceMixed when there is a mix of proxy reg and tproxy?
|
// TODO (freddy) Should we have a TopologySourceMixed when there is a mix of proxy reg and tproxy?
|
||||||
// Currently we label as proxy-registration if ANY instance has the explicit upstream definition.
|
// Currently we label as proxy-registration if ANY instance has the explicit upstream definition.
|
||||||
|
@ -143,6 +151,46 @@ func (c *TransparentProxyConfig) IsZero() bool {
|
||||||
return *c == zeroVal
|
return *c == zeroVal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AccessLogsConfig contains the associated default settings for all Envoy instances within the datacenter or partition
|
||||||
|
type AccessLogsConfig struct {
|
||||||
|
// Enabled turns off all access logging
|
||||||
|
Enabled bool `json:",omitempty" alias:"enabled"`
|
||||||
|
|
||||||
|
// DisableListenerLogs turns off just listener logs for connections rejected by Envoy because they don't
|
||||||
|
// have a matching listener filter.
|
||||||
|
DisableListenerLogs bool `json:",omitempty" alias:"disable_listener_logs"`
|
||||||
|
|
||||||
|
// Type selects the output for logs: "file", "stderr". "stdout"
|
||||||
|
Type LogSinkType `json:",omitempty" alias:"type"`
|
||||||
|
|
||||||
|
// Path is the output file to write logs
|
||||||
|
Path string `json:",omitempty" alias:"path"`
|
||||||
|
|
||||||
|
// The presence of one format string or the other implies the access log string encoding.
|
||||||
|
// Defining Both is invalid.
|
||||||
|
JSONFormat string `json:",omitempty" alias:"json_format"`
|
||||||
|
TextFormat string `json:",omitempty" alias:"text_format"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AccessLogsConfig) ToAPI() *api.AccessLogsConfig {
|
||||||
|
if c.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &api.AccessLogsConfig{
|
||||||
|
Enabled: c.Enabled,
|
||||||
|
DisableListenerLogs: c.DisableListenerLogs,
|
||||||
|
Type: api.LogSinkType(c.Type),
|
||||||
|
Path: c.Path,
|
||||||
|
JSONFormat: c.JSONFormat,
|
||||||
|
TextFormat: c.TextFormat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AccessLogsConfig) IsZero() bool {
|
||||||
|
zeroVal := AccessLogsConfig{}
|
||||||
|
return *c == zeroVal
|
||||||
|
}
|
||||||
|
|
||||||
// ConnectProxyConfig describes the configuration needed for any proxy managed
|
// ConnectProxyConfig describes the configuration needed for any proxy managed
|
||||||
// or unmanaged. It describes a single logical service's listener and optionally
|
// or unmanaged. It describes a single logical service's listener and optionally
|
||||||
// upstreams and sidecar-related config for a single instance. To describe a
|
// upstreams and sidecar-related config for a single instance. To describe a
|
||||||
|
|
|
@ -122,6 +122,35 @@ type ExposePath struct {
|
||||||
ParsedFromCheck bool
|
ParsedFromCheck bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LogSinkType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FileLogSinkType LogSinkType = "file"
|
||||||
|
StdErrLogSinkType LogSinkType = "stderr"
|
||||||
|
StdOutLogSinkType LogSinkType = "stdout"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccessLogsConfig contains the associated default settings for all Envoy instances within the datacenter or partition
|
||||||
|
type AccessLogsConfig struct {
|
||||||
|
// Enabled turns off all access logging
|
||||||
|
Enabled bool `json:",omitempty" alias:"enabled"`
|
||||||
|
|
||||||
|
// DisableListenerLogs turns off just listener logs for connections rejected by Envoy because they don't
|
||||||
|
// have a matching listener filter.
|
||||||
|
DisableListenerLogs bool `json:",omitempty" alias:"disable_listener_logs"`
|
||||||
|
|
||||||
|
// Type selects the output for logs: "file", "stderr". "stdout"
|
||||||
|
Type LogSinkType `json:",omitempty" alias:"type"`
|
||||||
|
|
||||||
|
// Path is the output file to write logs
|
||||||
|
Path string `json:",omitempty" alias:"path"`
|
||||||
|
|
||||||
|
// The presence of one format string or the other implies the access log string encoding.
|
||||||
|
// Defining Both is invalid.
|
||||||
|
JSONFormat string `json:",omitempty" alias:"json_format"`
|
||||||
|
TextFormat string `json:",omitempty" alias:"text_format"`
|
||||||
|
}
|
||||||
|
|
||||||
type UpstreamConfiguration struct {
|
type UpstreamConfiguration struct {
|
||||||
// Overrides is a slice of per-service configuration. The name field is
|
// Overrides is a slice of per-service configuration. The name field is
|
||||||
// required.
|
// required.
|
||||||
|
@ -266,6 +295,7 @@ type ProxyConfigEntry struct {
|
||||||
Config map[string]interface{} `json:",omitempty"`
|
Config map[string]interface{} `json:",omitempty"`
|
||||||
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||||
Expose ExposeConfig `json:",omitempty"`
|
Expose ExposeConfig `json:",omitempty"`
|
||||||
|
AccessLogs AccessLogsConfig `json:",omitempty"`
|
||||||
|
|
||||||
Meta map[string]string `json:",omitempty"`
|
Meta map[string]string `json:",omitempty"`
|
||||||
CreateIndex uint64
|
CreateIndex uint64
|
||||||
|
|
|
@ -401,6 +401,13 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
"TransparentProxy": {
|
"TransparentProxy": {
|
||||||
"OutboundListenerPort": 808,
|
"OutboundListenerPort": 808,
|
||||||
"DialedDirectly": true
|
"DialedDirectly": true
|
||||||
|
},
|
||||||
|
"AccessLogs": {
|
||||||
|
"Enabled": true,
|
||||||
|
"DisableListenerLogs": true,
|
||||||
|
"Type": "file",
|
||||||
|
"Path": "/tmp/logs.txt",
|
||||||
|
"TextFormat": "[%START_TIME%]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -426,6 +433,13 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
OutboundListenerPort: 808,
|
OutboundListenerPort: 808,
|
||||||
DialedDirectly: true,
|
DialedDirectly: true,
|
||||||
},
|
},
|
||||||
|
AccessLogs: AccessLogsConfig{
|
||||||
|
Enabled: true,
|
||||||
|
DisableListenerLogs: true,
|
||||||
|
Type: FileLogSinkType,
|
||||||
|
Path: "/tmp/logs.txt",
|
||||||
|
TextFormat: "[%START_TIME%]",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue