diff --git a/actions/reconfigure.go b/actions/reconfigure.go
index 2c52bd05..2df9c110 100644
--- a/actions/reconfigure.go
+++ b/actions/reconfigure.go
@@ -15,11 +15,12 @@ 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)
@@ -27,12 +28,14 @@ type Reconfigurable interface {
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"`
@@ -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,
@@ -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,
}
diff --git a/actions/reconfigure_test.go b/actions/reconfigure_test.go
index 3a4ca415..af6143bc 100644
--- a/actions/reconfigure_test.go
+++ b/actions/reconfigure_test.go
@@ -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,
}
diff --git a/docs/config.md b/docs/config.md
index 1686fc7e..9cb323db 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -16,6 +16,8 @@ The following environment variables can be used to configure the *Docker Flow Pr
|CONNECTION_MODE |HAProxy supports 5 connection modes.
`http-keep-alive`: all requests and responses are processed.
`http-tunnel`: only the first request and response are processed, everything else is forwarded with no analysis.
`httpclose`: tunnel with "Connection: close" added in both directions.
`http-server-close`: the server-facing connection is closed after the response.
`forceclose`: the connection is actively closed after end of response.
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 | | |
diff --git a/proxy/ha_proxy.go b/proxy/ha_proxy.go
index 4a13efb9..d3ffa6ca 100644
--- a/proxy/ha_proxy.go
+++ b/proxy/ha_proxy.go
@@ -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`
@@ -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
diff --git a/proxy/ha_proxy_test.go b/proxy/ha_proxy_test.go
index 5d066f9f..48beb6db 100644
--- a/proxy/ha_proxy_test.go
+++ b/proxy/ha_proxy_test.go
@@ -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")
@@ -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