Skip to content

Commit 80089c7

Browse files
gollerdanielnelson
authored andcommitted
Add better user-facing errors for API timeouts (influxdata#6016)
1 parent ba39d7b commit 80089c7

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

plugins/inputs/docker/docker.go

+52-17
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ type Docker struct {
5151

5252
client Client
5353
httpClient *http.Client
54-
engine_host string
54+
engineHost string
5555
serverVersion string
5656
filtersCreated bool
5757
labelFilter filter.Filter
@@ -122,12 +122,15 @@ var sampleConfig = `
122122
# insecure_skip_verify = false
123123
`
124124

125+
// SampleConfig returns the default Docker TOML configuration.
126+
func (d *Docker) SampleConfig() string { return sampleConfig }
127+
128+
// Description the metrics returned.
125129
func (d *Docker) Description() string {
126130
return "Read metrics about docker containers"
127131
}
128132

129-
func (d *Docker) SampleConfig() string { return sampleConfig }
130-
133+
// Gather metrics from the docker server.
131134
func (d *Docker) Gather(acc telegraf.Accumulator) error {
132135
if d.client == nil {
133136
c, err := d.getNewClient()
@@ -185,7 +188,11 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error {
185188
}
186189
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
187190
defer cancel()
191+
188192
containers, err := d.client.ContainerList(ctx, opts)
193+
if err == context.DeadlineExceeded {
194+
return errListTimeout
195+
}
189196
if err != nil {
190197
return err
191198
}
@@ -196,10 +203,8 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error {
196203
for _, container := range containers {
197204
go func(c types.Container) {
198205
defer wg.Done()
199-
err := d.gatherContainer(c, acc)
200-
if err != nil {
201-
acc.AddError(fmt.Errorf("E! Error gathering container %s stats: %s\n",
202-
c.Names, err.Error()))
206+
if err := d.gatherContainer(c, acc); err != nil {
207+
acc.AddError(err)
203208
}
204209
}(container)
205210
}
@@ -211,7 +216,11 @@ func (d *Docker) Gather(acc telegraf.Accumulator) error {
211216
func (d *Docker) gatherSwarmInfo(acc telegraf.Accumulator) error {
212217
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
213218
defer cancel()
219+
214220
services, err := d.client.ServiceList(ctx, types.ServiceListOptions{})
221+
if err == context.DeadlineExceeded {
222+
return errServiceTimeout
223+
}
215224
if err != nil {
216225
return err
217226
}
@@ -280,19 +289,24 @@ func (d *Docker) gatherInfo(acc telegraf.Accumulator) error {
280289
dataFields := make(map[string]interface{})
281290
metadataFields := make(map[string]interface{})
282291
now := time.Now()
292+
283293
// Get info from docker daemon
284294
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
285295
defer cancel()
296+
286297
info, err := d.client.Info(ctx)
298+
if err == context.DeadlineExceeded {
299+
return errInfoTimeout
300+
}
287301
if err != nil {
288302
return err
289303
}
290304

291-
d.engine_host = info.Name
305+
d.engineHost = info.Name
292306
d.serverVersion = info.ServerVersion
293307

294308
tags := map[string]string{
295-
"engine_host": d.engine_host,
309+
"engine_host": d.engineHost,
296310
"server_version": d.serverVersion,
297311
}
298312

@@ -403,7 +417,7 @@ func (d *Docker) gatherContainer(
403417
imageName, imageVersion := parseImage(container.Image)
404418

405419
tags := map[string]string{
406-
"engine_host": d.engine_host,
420+
"engine_host": d.engineHost,
407421
"server_version": d.serverVersion,
408422
"container_name": cname,
409423
"container_image": imageName,
@@ -412,17 +426,22 @@ func (d *Docker) gatherContainer(
412426

413427
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
414428
defer cancel()
429+
415430
r, err := d.client.ContainerStats(ctx, container.ID, false)
431+
if err == context.DeadlineExceeded {
432+
return errStatsTimeout
433+
}
416434
if err != nil {
417-
return fmt.Errorf("Error getting docker stats: %s", err.Error())
435+
return fmt.Errorf("error getting docker stats: %v", err)
418436
}
437+
419438
defer r.Body.Close()
420439
dec := json.NewDecoder(r.Body)
421440
if err = dec.Decode(&v); err != nil {
422441
if err == io.EOF {
423442
return nil
424443
}
425-
return fmt.Errorf("Error decoding: %s", err.Error())
444+
return fmt.Errorf("error decoding: %v", err)
426445
}
427446
daemonOSType := r.OSType
428447

@@ -438,19 +457,35 @@ func (d *Docker) gatherContainer(
438457
}
439458
}
440459

460+
return d.gatherContainerInspect(container, acc, tags, daemonOSType, v)
461+
}
462+
463+
func (d *Docker) gatherContainerInspect(
464+
container types.Container,
465+
acc telegraf.Accumulator,
466+
tags map[string]string,
467+
daemonOSType string,
468+
v *types.StatsJSON,
469+
) error {
470+
ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration)
471+
defer cancel()
472+
441473
info, err := d.client.ContainerInspect(ctx, container.ID)
474+
if err == context.DeadlineExceeded {
475+
return errInspectTimeout
476+
}
442477
if err != nil {
443-
return fmt.Errorf("Error inspecting docker container: %s", err.Error())
478+
return fmt.Errorf("error inspecting docker container: %v", err)
444479
}
445480

446481
// Add whitelisted environment variables to tags
447482
if len(d.TagEnvironment) > 0 {
448483
for _, envvar := range info.Config.Env {
449484
for _, configvar := range d.TagEnvironment {
450-
dock_env := strings.SplitN(envvar, "=", 2)
485+
dockEnv := strings.SplitN(envvar, "=", 2)
451486
//check for presence of tag in whitelist
452-
if len(dock_env) == 2 && len(strings.TrimSpace(dock_env[1])) != 0 && configvar == dock_env[0] {
453-
tags[dock_env[0]] = dock_env[1]
487+
if len(dockEnv) == 2 && len(strings.TrimSpace(dockEnv[1])) != 0 && configvar == dockEnv[0] {
488+
tags[dockEnv[0]] = dockEnv[1]
454489
}
455490
}
456491
}
@@ -800,7 +835,7 @@ func sliceContains(in string, sl []string) bool {
800835
func parseSize(sizeStr string) (int64, error) {
801836
matches := sizeRegex.FindStringSubmatch(sizeStr)
802837
if len(matches) != 4 {
803-
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
838+
return -1, fmt.Errorf("invalid size: %s", sizeStr)
804839
}
805840

806841
size, err := strconv.ParseFloat(matches[1], 64)

plugins/inputs/docker/errors.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package docker
2+
3+
import "errors"
4+
5+
var (
6+
errInfoTimeout = errors.New("timeout retrieving docker engine info")
7+
errStatsTimeout = errors.New("timeout retrieving container stats")
8+
errInspectTimeout = errors.New("timeout retrieving container environment")
9+
errListTimeout = errors.New("timeout retrieving container list")
10+
errServiceTimeout = errors.New("timeout retrieving swarm service list")
11+
)

0 commit comments

Comments
 (0)