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 HTTP timeout to Splunk logger, fixes #43000 #43001
base: master
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,7 @@ const ( | |
splunkGzipCompressionKey = "splunk-gzip" | ||
splunkGzipCompressionLevelKey = "splunk-gzip-level" | ||
splunkIndexAcknowledgment = "splunk-index-acknowledgment" | ||
splunkHTTPTimeout = "splunk-timeout" | ||
envKey = "env" | ||
envRegexKey = "env-regex" | ||
labelsKey = "labels" | ||
|
@@ -228,12 +229,23 @@ func New(info logger.Info) (logger.Logger, error) { | |
} | ||
} | ||
|
||
var timeout time.Duration | ||
if timeoutStr, ok := info.Config[splunkHTTPTimeout]; ok { | ||
value, err := strconv.ParseInt(timeoutStr, 10, 64) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
timeout = time.Duration(value) * time.Millisecond | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for updating. Erm, I thought I commented, but looks like I never did 😬 Similar to my comment on #43100 (comment), I'm wondering if we should make the
Happy to hear your thoughts! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Of course, that sounds like a good suggestion. Sorry for missing it. I will get to it asap. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added the duration string support and am testing for negative values. I didn't enforce min/max, given that the default is no timeout, it doesn't make sense to bound max value. |
||
} | ||
|
||
transport := &http.Transport{ | ||
TLSClientConfig: tlsConfig, | ||
Proxy: http.ProxyFromEnvironment, | ||
} | ||
client := &http.Client{ | ||
Transport: transport, | ||
Timeout: timeout, | ||
atoulme marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
source := info.Config[splunkSourceKey] | ||
|
@@ -584,6 +596,7 @@ func ValidateLogOpt(cfg map[string]string) error { | |
case splunkGzipCompressionKey: | ||
case splunkGzipCompressionLevelKey: | ||
case splunkIndexAcknowledgment: | ||
case splunkHTTPTimeout: | ||
case envKey: | ||
case envRegexKey: | ||
case labelsKey: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import ( | |
"compress/gzip" | ||
"context" | ||
"fmt" | ||
"net" | ||
"net/http" | ||
"os" | ||
"runtime" | ||
|
@@ -1392,3 +1393,59 @@ func TestDeadlockOnBlockedEndpoint(t *testing.T) { | |
case <-done: | ||
} | ||
} | ||
|
||
func TestCustomHttpTimeout(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: this should be named |
||
tcpAddr := &net.TCPAddr{IP: []byte{127, 0, 0, 1}, Port: 0, Zone: ""} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tcpAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)} |
||
tcpListener, err := net.ListenTCP("tcp", tcpAddr) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
counter := 0 | ||
Comment on lines
+1402
to
+1403
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps would be slightly cleaner to move the }
defer tcpListener.Close()
conter := 0 (I think it's ok to ignore error handling) |
||
go http.Serve(tcpListener, http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { | ||
if request.Method == "POST" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that we're already importing the if request.Method == http.MethodPost { |
||
counter++ | ||
// block so connection will timeout. | ||
time.Sleep(5000 * time.Millisecond) | ||
} | ||
writer.WriteHeader(200) | ||
})) | ||
|
||
info := logger.Info{ | ||
Config: map[string]string{ | ||
splunkURLKey: "http://" + tcpListener.Addr().String(), | ||
splunkTokenKey: "1234", | ||
splunkHTTPTimeout: "100", | ||
}, | ||
ContainerID: "containeriid", | ||
ContainerName: "/container_name", | ||
ContainerImageID: "contaimageid", | ||
ContainerImageName: "container_image_name", | ||
} | ||
|
||
loggerDriver, err := New(info) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
batchSendTimeout = 1 * time.Second | ||
start := time.Now() | ||
if err := loggerDriver.Log(&logger.Message{Line: []byte("message1"), Source: "stdout", Timestamp: time.Now()}); err != nil { | ||
t.Fatal(err) | ||
} | ||
err = loggerDriver.Close() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
duration := time.Since(start) | ||
if duration > 1*time.Second { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should likely take the value we set above, to prevent this check from accidentally being out of sync if that value would ever be changed;
I'm a bit worried that this could become a bit "flaky"; time taken could possibly be "slightly more than 1 second" and make the test randomly fail. For such cases it may be good to give it a "bit" more time (and leave a comment that describes we're doing so). Something like; // check that the timeout is used, but give it a bit more time to prevent
// the test to become flaky.
if duration > batchSendTimeout+75*time.Millisecond { There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm.... so looking at this... I'm now wondering if this PR is doing the right thing (I'll leave another comment describing what I mean) |
||
t.Fatal("Sending didn't use the custom timeout") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps include the actual time in the error; t.Fatalf("Sending didn't use the custom timeout: took %v", duration) |
||
} | ||
if counter == 0 { | ||
t.Fatal("No messages received") | ||
} | ||
|
||
err = tcpListener.Close() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should wrap (
errors.Wrap()
) the error to give the error a bit more context. Currently it would produce something liketime: unknown unit "msec" in duration "100msec"
, what describes what's wrong with the value, but still makes it difficult for the user to find "what value was this?". Something like:Which would produce: