Skip to content

Commit

Permalink
Added the option to customize HTTP and TCP logging [fixes #193]
Browse files Browse the repository at this point in the history
  • Loading branch information
vfarcic committed Apr 3, 2017
1 parent 353e302 commit efec1c1
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 7 deletions.
17 changes: 12 additions & 5 deletions actions/reconfigure.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,27 @@ import (
"sync"
)

const ServiceTemplateFeFilename = "service-formatted-fe.ctmpl"
const ServiceTemplateBeFilename = "service-formatted-be.ctmpl"
const serviceTemplateFeFilename = "service-formatted-fe.ctmpl"
const serviceTemplateBeFilename = "service-formatted-be.ctmpl"

var mu = &sync.Mutex{}

// Methods that should be created for reconfigure actions
type Reconfigurable interface {
Executable
GetData() (BaseReconfigure, proxy.Service)
ReloadServicesFromListener(addresses []string, instanceName, mode, listenerAddress string) error
GetTemplates(sr *proxy.Service) (front, back string, err error)
}

// Data structure that holds reconfigure data
type Reconfigure struct {
BaseReconfigure
proxy.Service
Mode string `short:"m" long:"mode" env:"MODE" description:"If set to 'swarm', proxy will operate assuming that Docker service from v1.12+ is used."`
}

// Base structure
type BaseReconfigure struct {
ConsulAddresses []string
ConfigsPath string `short:"c" long:"configs-path" default:"/cfg" description:"The path to the configurations directory"`
Expand All @@ -41,9 +44,13 @@ type BaseReconfigure struct {
skipAddressValidation bool `env:"SKIP_ADDRESS_VALIDATION" description:"Whether to skip validating service address before reconfiguring the proxy."`
}

// Singleton instance
var ReconfigureInstance Reconfigure

// TODO: Change proxy.Service to *proxy.Service
/*
Creates new instance of the Reconfigurable interface
TODO: Change proxy.Service to *proxy.Service
*/
var NewReconfigure = func(baseData BaseReconfigure, serviceData proxy.Service, mode string) Reconfigurable {
return &Reconfigure{
BaseReconfigure: baseData,
Expand Down Expand Up @@ -209,9 +216,9 @@ func (m *Reconfigure) createConfigs(templatesPath string, sr *proxy.Service) err
args := registry.CreateConfigsArgs{
Addresses: m.ConsulAddresses,
TemplatesPath: templatesPath,
FeFile: ServiceTemplateFeFilename,
FeFile: serviceTemplateFeFilename,
FeTemplate: feTemplate,
BeFile: ServiceTemplateBeFilename,
BeFile: serviceTemplateBeFilename,
BeTemplate: beTemplate,
ServiceName: sr.ServiceName,
}
Expand Down
4 changes: 2 additions & 2 deletions actions/reconfigure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,9 @@ func (s ReconfigureTestSuite) Test_Execute_InvokesRegistrarableCreateConfigs() {
expectedArgs := registry.CreateConfigsArgs{
Addresses: []string{s.ConsulAddress},
TemplatesPath: s.TemplatesPath,
FeFile: ServiceTemplateFeFilename,
FeFile: serviceTemplateFeFilename,
FeTemplate: "",
BeFile: ServiceTemplateBeFilename,
BeFile: serviceTemplateBeFilename,
BeTemplate: s.ConsulTemplateBe,
ServiceName: s.ServiceName,
}
Expand Down
2 changes: 2 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ The following environment variables can be used to configure the *Docker Flow Pr
|CONNECTION_MODE |HAProxy supports 5 connection modes.<br><br>`http-keep-alive`: all requests and responses are processed.<br>`http-tunnel`: only the first request and response are processed, everything else is forwarded with no analysis.<br>`httpclose`: tunnel with "Connection: close" added in both directions.<br>`http-server-close`: the server-facing connection is closed after the response.<br>`forceclose`: the connection is actively closed after end of response.<br><br>In general, it is preferred to use `http-server-close` with application servers, and some static servers might benefit from `http-keep-alive`.|No|http-server-close|http-keep-alive|
|DEBUG |Enables logging of each request sent through the proxy. Please consult [Debug Format](#debug-format) for info about the log entries. This feature should be used with caution. **Do not enable debugging in production unless necessary.**|No|false|true|
|DEBUG_ERRORS_ONLY |If set to `true`, only requests that resulted in an error, timeout, retry, and redispatch will be logged. If a request is HTTP, responses with a status 5xx will be logged too. This variable will take effect only if `DEBUG` is set to `true`.|No|false|true|
|DEBUG_HTTP_FORMAT |Logging format that will be used with HTTP requests. Please consult [Custom log format](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#8.2.4) for more info about the available options.|No| | |
|DEBUG_TCP_FORMAT |Logging format that will be used with TCP requests. Please consult [Custom log format](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#8.2.4) for more info about the available options.|No| | |
|DEFAULT_PORTS |The default ports used by the proxy. Multiple values can be separated with comma (`,`). If a port should be for SSL connections, append it with `:ssl.|No|80,443:ssl| |
|EXTRA_FRONTEND |Value will be added to the default `frontend` configuration.|No | | |
|EXTRA_GLOBAL |Value will be added to the default `global` configuration.|No | | |
Expand Down
14 changes: 14 additions & 0 deletions proxy/ha_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ func (m HaProxy) getConfigData() ConfigData {
d.ExtraFrontend += `
option httplog
log global`
format := GetSecretOrEnvVar("DEBUG_HTTP_FORMAT", "")
if len(format) > 0 {
d.ExtraFrontend += fmt.Sprintf(`
log-format %s`,
format,
)
}
if strings.EqualFold(GetSecretOrEnvVar("DEBUG_ERRORS_ONLY", ""), "true") {
d.ExtraDefaults += `
option dontlog-normal`
Expand Down Expand Up @@ -345,6 +352,13 @@ frontend tcpFE_%d
tmpl += `
option tcplog
log global`
format := GetSecretOrEnvVar("DEBUG_TCP_FORMAT", "")
if len(format) > 0 {
tmpl += fmt.Sprintf(`
log-format %s`,
format,
)
}
}
for _, s := range services {
var backend string
Expand Down
67 changes: 67 additions & 0 deletions proxy/ha_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,32 @@ func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsLogging_WhenDebug()
s.Equal(expectedData, actualData)
}

func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsHttpLogFormat_WhenSpecified() {
debugOrig := os.Getenv("DEBUG")
debugHttpFormatOrig := os.Getenv("DEBUG_HTTP_FORMAT")
defer func() {
os.Setenv("DEBUG", debugOrig)
os.Setenv("DEBUG_HTTP_FORMAT", debugHttpFormatOrig)
}()
os.Setenv("DEBUG", "true")
os.Setenv("DEBUG_HTTP_FORMAT", "something")
var actualData string
expectedData := fmt.Sprintf(
`%s
log-format something%s`,
s.getTemplateWithLogs(),
s.ServicesContent,
)
writeFile = func(filename string, data []byte, perm os.FileMode) error {
actualData = string(data)
return nil
}

NewHaProxy(s.TemplatesPath, s.ConfigsPath).CreateConfigFromTemplates()

s.Equal(expectedData, actualData)
}

func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsDoNotLogNormal_WhenDebugErrorsOnlyIsSet() {
debugOrig := os.Getenv("DEBUG")
debugErrorsOnlyOrig := os.Getenv("DEBUG")
Expand Down Expand Up @@ -677,6 +703,47 @@ frontend tcpFE_1234
s.Equal(expectedData, actualData)
}

func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsTcpLoggingFormat() {
debugOrig := os.Getenv("DEBUG")
debugTcpFormatOrig := os.Getenv("DEBUG_TCP_FORMAT")
defer func() {
os.Setenv("DEBUG", debugOrig)
os.Setenv("DEBUG_TCP_FORMAT", debugTcpFormatOrig)
}()
os.Setenv("DEBUG", "true")
os.Setenv("DEBUG_TCP_FORMAT", "something-tcp-related")
var actualData string
expectedData := fmt.Sprintf(
`%s
frontend tcpFE_1234
bind *:1234
mode tcp
option tcplog
log global
log-format something-tcp-related
default_backend my-service-1-be1234%s`,
s.getTemplateWithLogs(),
s.ServicesContent,
)
writeFile = func(filename string, data []byte, perm os.FileMode) error {
actualData = string(data)
return nil
}
p := NewHaProxy(s.TemplatesPath, s.ConfigsPath)
data.Services["my-service-1"] = Service{
ReqMode: "tcp",
ServiceName: "my-service-1",
ServiceDest: []ServiceDest{
{SrcPort: 1234, Port: "4321"},
},
}

p.CreateConfigFromTemplates()

s.Equal(expectedData, actualData)
}

func (s HaProxyTestSuite) Test_CreateConfigFromTemplates_AddsContentFrontEndSNI() {
var actualData string
tmpl := s.TemplateContent
Expand Down

0 comments on commit efec1c1

Please sign in to comment.