Skip to content

Commit 1c0fe22

Browse files
authored
Merge pull request #3 from sysdiglabs/master
Sync
2 parents 3aa5e0c + 674b495 commit 1c0fe22

File tree

15 files changed

+252
-35
lines changed

15 files changed

+252
-35
lines changed

.drone.yml

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ services:
6868

6969
steps:
7070
- name: start
71-
image: "golang:1.16"
71+
image: "golang:1.17"
7272
commands:
7373
- sleep 10
7474
- 'echo "start"'
@@ -99,7 +99,7 @@ steps:
9999
- start
100100

101101
- name: build-binaries
102-
image: "golang:1.16"
102+
image: "golang:1.17"
103103
pull: always
104104
environment:
105105
GO111MODULE: on
@@ -139,7 +139,7 @@ steps:
139139
- start
140140

141141
- name: lint
142-
image: golangci/golangci-lint:latest-alpine
142+
image: golangci/golangci-lint@sha256:39e13a431c69fca37f88ab4b2340655eef7d7d18373df10d5e737f0b77866747
143143
pull: always
144144
commands:
145145
- apk add --update make
@@ -153,7 +153,7 @@ steps:
153153
- start
154154

155155
- name: tests
156-
image: "golang:1.16"
156+
image: "golang:1.17"
157157
pull: always
158158
environment:
159159
GO111MODULE: on
@@ -164,17 +164,20 @@ steps:
164164
- sleep 5
165165
- make checks
166166
- make test
167-
- make upload-coverage
167+
# coveralls seems to have issues right now
168+
# https://github.com/lemurheavy/coveralls-public/issues/1573
169+
# - make upload-coverage
168170
when:
169171
event:
170172
- pull_request
171173
- push
174+
- tag
172175
depends_on:
173176
- build-binaries
174177

175178

176179
- name: mixins
177-
image: golang:1.16
180+
image: golang:1.17
178181
commands:
179182
- cd ./contrib/redis-mixin
180183
- go install github.com/monitoring-mixins/mixtool/cmd/mixtool
@@ -292,8 +295,95 @@ steps:
292295
- tests
293296

294297

298+
###########
299+
#
300+
# Mirroring the docker images to quay.io
301+
#
302+
- name: release-quay-scratch
303+
image: plugins/docker
304+
settings:
305+
registry: "quay.io"
306+
repo: "quay.io/oliver006/redis_exporter"
307+
tags: "latest,latest-amd64,${DRONE_TAG},${DRONE_TAG}-amd64"
308+
dockerfile: ./docker/Dockerfile.amd64
309+
target: scratch
310+
build_args:
311+
- 'TAG=${DRONE_TAG}'
312+
- 'SHA1=${DRONE_COMMIT_SHA}'
313+
- 'GOARCH=amd64'
314+
config:
315+
from_secret: docker_config_json
316+
when:
317+
event:
318+
- tag
319+
depends_on:
320+
- tests
321+
322+
323+
- name: release-quay-alpine-arm64
324+
image: plugins/docker
325+
settings:
326+
registry: "quay.io"
327+
repo: "quay.io/oliver006/redis_exporter"
328+
tags: "latest-arm64,${DRONE_TAG}-arm64"
329+
dockerfile: ./docker/Dockerfile.arm64
330+
target: alpine-arm64
331+
build_args:
332+
- 'TAG=${DRONE_TAG}'
333+
- 'SHA1=${DRONE_COMMIT_SHA}'
334+
- 'GOARCH=arm64'
335+
config:
336+
from_secret: docker_config_json
337+
when:
338+
event:
339+
- tag
340+
depends_on:
341+
- tests
342+
343+
344+
- name: release-quay-alpine-arm
345+
image: plugins/docker
346+
settings:
347+
registry: "quay.io"
348+
repo: "quay.io/oliver006/redis_exporter"
349+
tags: "latest-arm,${DRONE_TAG}-arm"
350+
dockerfile: ./docker/Dockerfile.arm
351+
target: alpine-arm
352+
build_args:
353+
- 'TAG=${DRONE_TAG}'
354+
- 'SHA1=${DRONE_COMMIT_SHA}'
355+
- 'GOARCH=arm'
356+
config:
357+
from_secret: docker_config_json
358+
when:
359+
event:
360+
- tag
361+
depends_on:
362+
- tests
363+
364+
365+
- name: release-quay-alpine-amd64
366+
image: plugins/docker
367+
settings:
368+
registry: "quay.io"
369+
repo: "quay.io/oliver006/redis_exporter"
370+
tags: "alpine,${DRONE_TAG}-alpine"
371+
dockerfile: ./docker/Dockerfile.amd64
372+
target: alpine
373+
build_args:
374+
- 'TAG=${DRONE_TAG}'
375+
- 'SHA1=${DRONE_COMMIT_SHA}'
376+
- 'GOARCH=amd64'
377+
config:
378+
from_secret: docker_config_json
379+
when:
380+
event:
381+
- tag
382+
depends_on:
383+
- tests
384+
295385
- name: release-github-binaries
296-
image: "golang:1.16"
386+
image: "golang:1.17"
297387
pull: always
298388
environment:
299389
GITHUB_TOKEN:

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ mixin:
6060

6161
.PHONY: upload-coverage
6262
upload-coverage:
63-
go get github.com/mattn/goveralls
63+
go install github.com/mattn/goveralls@v0.0.9
6464
/go/bin/goveralls -coverprofile=coverage.txt -service=drone.io
6565

6666

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,15 @@ You can run it like this:
203203
docker run -d --name redis_exporter -p 9121:9121 oliver006/redis_exporter
204204
```
205205

206+
Docker images are also published to the [quay.io docker repo](https://quay.io/oliver006/redis_exporter) so you can pull them from there if for instance you run into rate limiting issues with Docker hub.
207+
208+
```sh
209+
docker run -d --name redis_exporter -p 9121:9121 quay.io/oliver006/redis_exporter
210+
```
211+
206212
The `latest` docker image contains only the exporter binary.
207-
If, e.g. for debugging purposes, you need the exporter running
208-
in an image that has a shell, etc then you can run the `alpine` image:
213+
If e.g. for debugging purposes, you need the exporter running
214+
in an image that has a shell then you can run the `alpine` image:
209215

210216
```sh
211217
docker run -d --name redis_exporter -p 9121:9121 oliver006/redis_exporter:alpine

contrib/docker-compose-for-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ services:
6161

6262

6363
tests:
64-
image: golang:1.16
64+
image: golang:1.17
6565
working_dir: /go/src/github.com/oliver006/redis_exporter
6666
volumes:
6767
- ..:/go/src/github.com/oliver006/redis_exporter

docker/Dockerfile.amd64

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# build container
33
#
4-
FROM golang:1.16-alpine as builder
4+
FROM golang:1.17-alpine as builder
55
WORKDIR /go/src/github.com/oliver006/redis_exporter/
66

77
ADD . /go/src/github.com/oliver006/redis_exporter/

docker/Dockerfile.arm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# build container
33
#
4-
FROM golang:1.16-alpine as builder
4+
FROM golang:1.17-alpine as builder
55
WORKDIR /go/src/github.com/oliver006/redis_exporter/
66

77
ADD . /go/src/github.com/oliver006/redis_exporter/

docker/Dockerfile.arm64

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#
22
# build container
33
#
4-
FROM golang:1.16-alpine as builder
4+
FROM golang:1.17-alpine as builder
55
WORKDIR /go/src/github.com/oliver006/redis_exporter/
66

77
ADD . /go/src/github.com/oliver006/redis_exporter/

exporter/clients.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package exporter
22

33
import (
44
"regexp"
5+
"strconv"
56
"strings"
7+
"time"
68

79
"github.com/gomodule/redigo/redis"
810
"github.com/prometheus/client_golang/prometheus"
@@ -28,15 +30,27 @@ func parseClientListString(clientInfo string) ([]string, bool) {
2830
connectedClient[vPart[0]] = vPart[1]
2931
}
3032

33+
createdAtTs, err := durationFieldToTimestamp(connectedClient["age"])
34+
if err != nil {
35+
log.Debugf("cloud not parse age field(%s): %s", connectedClient["age"], err.Error())
36+
return nil, false
37+
}
38+
39+
idleSinceTs, err := durationFieldToTimestamp(connectedClient["idle"])
40+
if err != nil {
41+
log.Debugf("cloud not parse idle field(%s): %s", connectedClient["idle"], err.Error())
42+
return nil, false
43+
}
44+
3145
hostPortString := strings.Split(connectedClient["addr"], ":")
3246
if len(hostPortString) != 2 {
3347
return nil, false
3448
}
3549

3650
return []string{
3751
connectedClient["name"],
38-
connectedClient["age"],
39-
connectedClient["idle"],
52+
createdAtTs,
53+
idleSinceTs,
4054
connectedClient["flags"],
4155
connectedClient["db"],
4256
connectedClient["omem"],
@@ -48,6 +62,15 @@ func parseClientListString(clientInfo string) ([]string, bool) {
4862

4963
}
5064

65+
func durationFieldToTimestamp(field string) (string, error) {
66+
parsed, err := strconv.ParseInt(field, 10, 64)
67+
if err != nil {
68+
return "", err
69+
}
70+
71+
return strconv.FormatInt(time.Now().Unix()-parsed, 10), nil
72+
}
73+
5174
func (e *Exporter) extractConnectedClientMetrics(ch chan<- prometheus.Metric, c redis.Conn) {
5275
reply, err := redis.String(doRedisCmd(c, "CLIENT", "LIST"))
5376
if err != nil {

exporter/clients_test.go

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,105 @@
11
package exporter
22

33
import (
4+
"strconv"
45
"strings"
56
"testing"
7+
"time"
68

79
"github.com/prometheus/client_golang/prometheus"
810
)
911

12+
func TestDurationFieldToTimestamp(t *testing.T) {
13+
nowTs := time.Now().Unix()
14+
for _, tst := range []struct {
15+
in string
16+
expectedOk bool
17+
expectedVal int64
18+
}{
19+
{
20+
in: "123",
21+
expectedOk: true,
22+
expectedVal: nowTs - 123,
23+
},
24+
{
25+
in: "0",
26+
expectedOk: true,
27+
expectedVal: nowTs - 0,
28+
},
29+
{
30+
in: "abc",
31+
expectedOk: false,
32+
},
33+
} {
34+
res, err := durationFieldToTimestamp(tst.in)
35+
if err == nil && !tst.expectedOk {
36+
t.Fatalf("expected not ok, but got no error, input: [%s]", tst.in)
37+
} else if err != nil && tst.expectedOk {
38+
t.Fatalf("expected ok, but got error: %s, input: [%s]", err, tst.in)
39+
}
40+
if tst.expectedOk {
41+
resInt64, err := strconv.ParseInt(res, 10, 64)
42+
if err != nil {
43+
t.Fatalf("ParseInt( %s ) err: %s", res, err)
44+
}
45+
if resInt64 != tst.expectedVal {
46+
t.Fatalf("expected %d, but got: %d", tst.expectedVal, resInt64)
47+
}
48+
}
49+
}
50+
}
51+
1052
func TestParseClientListString(t *testing.T) {
11-
tsts := map[string][]string{
12-
"id=11 addr=127.0.0.1:63508 fd=8 name= age=6321 idle=6320 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=setex": []string{"", "6321", "6320", "N", "0", "0", "setex", "127.0.0.1", "63508"},
13-
"id=14 addr=127.0.0.1:64958 fd=9 name=foo age=5 idle=0 flags=N db=1 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client": []string{"foo", "5", "0", "N", "1", "0", "client", "127.0.0.1", "64958"},
53+
convertDurationToTimestampString := func(duration string) string {
54+
ts, err := durationFieldToTimestamp(duration)
55+
if err != nil {
56+
panic(err)
57+
}
58+
return ts
59+
}
60+
61+
tsts := []struct {
62+
in string
63+
expectedOk bool
64+
expectedLbls []string
65+
}{
66+
{
67+
in: "id=11 addr=127.0.0.1:63508 fd=8 name= age=6321 idle=6320 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=setex",
68+
expectedOk: true,
69+
expectedLbls: []string{"", convertDurationToTimestampString("6321"), convertDurationToTimestampString("6320"), "N", "0", "0", "setex", "127.0.0.1", "63508"},
70+
}, {
71+
in: "id=14 addr=127.0.0.1:64958 fd=9 name=foo age=5 idle=0 flags=N db=1 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client",
72+
expectedOk: true,
73+
expectedLbls: []string{"foo", convertDurationToTimestampString("5"), convertDurationToTimestampString("0"), "N", "1", "0", "client", "127.0.0.1", "64958"},
74+
}, {
75+
in: "id=14 addr=127.0.0.1:64958 fd=9 name=foo age=ABCDE idle=0 flags=N db=1 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client",
76+
expectedOk: false,
77+
}, {
78+
in: "id=14 addr=127.0.0.1:64958 fd=9 name=foo age=5 idle=NOPE flags=N db=1 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client",
79+
expectedOk: false,
80+
}, {
81+
in: "",
82+
expectedOk: false,
83+
},
1484
}
1585

16-
for k, v := range tsts {
17-
lbls, ok := parseClientListString(k)
86+
for _, tst := range tsts {
87+
lbls, ok := parseClientListString(tst.in)
88+
if !tst.expectedOk {
89+
if ok {
90+
t.Errorf("expected NOT ok, but got ok, input: %s", tst.in)
91+
}
92+
continue
93+
}
1894
mismatch := false
1995
for idx, l := range lbls {
20-
if l != v[idx] {
96+
if l != tst.expectedLbls[idx] {
2197
mismatch = true
2298
break
2399
}
24100
}
25-
if !ok || mismatch {
26-
t.Errorf("TestParseClientListString( %s ) error. Given: %s Wanted: %s", k, lbls, v)
101+
if mismatch {
102+
t.Errorf("TestParseClientListString( %s ) error. Given: %s Wanted: %s", tst.in, lbls, tst.expectedLbls)
27103
}
28104
}
29105
}

exporter/exporter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ func NewRedisExporter(redisURI string, opts Options) (*Exporter, error) {
310310

311311
e.metricDescriptions = map[string]*prometheus.Desc{}
312312

313-
connectedClientsLabels := []string{"name", "age", "idle", "flags", "db", "omem", "cmd", "host"}
313+
connectedClientsLabels := []string{"name", "created_at", "idle_since", "flags", "db", "omem", "cmd", "host"}
314314
if e.options.ExportClientsInclPort {
315315
connectedClientsLabels = append(connectedClientsLabels, "port")
316316
}

0 commit comments

Comments
 (0)