Skip to content

Commit cbbc9d9

Browse files
authored
Merge branch 'main' into add-code-coverage-integration
2 parents 04a44cc + c17b537 commit cbbc9d9

File tree

19 files changed

+624
-1376
lines changed

19 files changed

+624
-1376
lines changed

.github/pull_request_template.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
[PMM-XXXX](https://jira.percona.com/browse/PMM-XXXX) (optional, if ticket reported)
22

3-
- [ ] Links to other linked pull requests (optional).
3+
- [ ] Links to related pull requests (optional).
44

55
---
66

7-
- [ ] Tests passed.
8-
- [ ] Fix conflicts with target branch.
9-
- [ ] Update jira ticket description if needed.
10-
- [ ] Attach screenshots/console output to confirm new behavior to jira ticket, if applicable.
7+
Below we provide a basic checklist of things that would make it a good PR:
8+
- Make sure to sign the CLA (Contributor License Agreement).
9+
- Make sure all tests pass.
10+
- Keep current with the target branch and fix conflicts if necessary.
11+
- Update jira ticket description if necessary.
12+
- Attach screenshots and/or console output to the jira ticket to confirm new behavior, if applicable.
13+
- Leave notes to the reviewers if you need to focus their attention on something specific.
1114

1215
Once all checks pass and the code is ready for review, please add `pmm-review-exporters` team as the reviewer. That would assign people from the review team automatically. Report any issues on our [Forum](https://forums.percona.com).

.github/workflows/go.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ jobs:
2020
fail-fast: false
2121
matrix:
2222
image:
23-
- mongo:4.2
2423
- mongo:4.4
2524
- mongo:5.0
26-
- percona/percona-server-mongodb:4.2
2725
- percona/percona-server-mongodb:4.4
2826
- percona/percona-server-mongodb:5.0
2927

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ jobs:
2323
go-version-file: ${{ github.workspace }}/go.mod
2424

2525
- name: Login to Docker Hub
26-
uses: docker/login-action@v2
26+
uses: docker/login-action@v3
2727
with:
2828
username: ${{ secrets.DOCKERHUB_USERNAME }}
2929
password: ${{ secrets.DOCKERHUB_TOKEN }}
3030

3131
- name: Login to GitHub Container Registry
32-
uses: docker/login-action@v2
32+
uses: docker/login-action@v3
3333
with:
3434
registry: ghcr.io
3535
username: ${{ github.actor }}
@@ -43,7 +43,7 @@ jobs:
4343
uses: docker/setup-buildx-action@v3
4444

4545
- name: Run GoReleaser
46-
uses: goreleaser/goreleaser-action@v4
46+
uses: goreleaser/goreleaser-action@v5
4747
with:
4848
version: latest
4949
args: release --rm-dist

Dockerfile

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
FROM alpine AS builder
22
RUN apk add --no-cache ca-certificates
33

4-
FROM scratch AS final
4+
FROM golang:alpine as builder2
5+
6+
RUN apk update && apk add make
7+
RUN mkdir /source
8+
COPY . /source
9+
WORKDIR /source
10+
RUN make init
11+
RUN make build
12+
13+
FROM alpine AS final
514
USER 65535:65535
6-
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
7-
COPY ./mongodb_exporter /
15+
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
16+
COPY --from=builder2 /source/mongodb_exporter /
817
EXPOSE 9216
918
ENTRYPOINT ["/mongodb_exporter"]

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ export MONGODB_PASSWORD=YYY
8686
mongodb_exporter_linux_amd64/mongodb_exporter --mongodb.uri=mongodb://127.0.0.1:17001 --mongodb.collstats-colls=db1.c1,db2.c2
8787
```
8888

89+
#### Multi-target support
90+
You can run the exporter specifying multiple URIs, devided by a comma in --mongodb.uri option or MONGODB_URI environment variable in order to monitor multiple mongodb instances with the a single mongodb_exporter instance.
91+
```sh
92+
--mongodb.uri=mongodb://user:[email protected]:27017/admin,mongodb://user2:[email protected]:27018/admin
93+
```
94+
In this case you can use the **/scrape** endpoint with the **target** parameter to retreive the specified tartget's metrics. When querying the data you can use just mongodb://host:port in the targer parameter without other parameters and, of course without host credentials
95+
```sh
96+
GET /scrape?target=mongodb://127.0.0.1:27018
97+
```
98+
99+
89100
#### Enabling collstats metrics gathering
90101
`--mongodb.collstats-colls` receives a list of databases and collections to monitor using collstats.
91102
Usage example: `--mongodb.collstats-colls=database1.collection1,database2.collection2`

REFERENCE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
|--web.listen-address|Address to listen on for web interface and telemetry|--web.listen-address=":9216"|
1515
|--web.telemetry-path|Metrics expose path|--web.telemetry-path="/metrics"|
1616
|--web.config|Path to the file having Prometheus TLS config for basic auth|--web.config=STRING|
17+
|--web.timeout-offset|Offset to subtract from the timeout in seconds|--web.timeout-offset=1|
1718
|--log.level|Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]|--log.level="error"|
1819
|--collector.diagnosticdata|Enable collecting metrics from getDiagnosticData|
1920
|--collector.replicasetstatus|Enable collecting metrics from replSetGetStatus|
@@ -27,4 +28,4 @@
2728
|--collector.profile-time-ts=30|Set time for scrape slow queries| This interval must be synchronized with the Prometheus scrape interval|
2829
|--collector.profile|Enable collecting metrics from profile|
2930
|--metrics.overridedescendingindex| Enable descending index name override to replace -1 with _DESC ||
30-
|--version|Show version and exit|
31+
|--version|Show version and exit|

exporter/base_collector.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ func newBaseCollector(client *mongo.Client, logger *logrus.Logger) *baseCollecto
4343
func (d *baseCollector) Describe(ctx context.Context, ch chan<- *prometheus.Desc, collect func(mCh chan<- prometheus.Metric)) {
4444
select {
4545
case <-ctx.Done():
46-
return
46+
// don't interrupt, let mongodb_up metric to be registered if on timeout we still don't have client connected
47+
if d.client != nil {
48+
return
49+
}
4750
default:
4851
}
4952

exporter/currentop_collector_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ import (
3131
)
3232

3333
func TestCurrentopCollector(t *testing.T) {
34+
// It seems like this test needs the queries to continue running so that current oplog is not empty.
35+
// TODO: figure out how to restore this test.
36+
t.Skip()
37+
3438
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
3539
defer cancel()
3640

exporter/exporter.go

Lines changed: 22 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,12 @@ import (
2121
"fmt"
2222
"net/http"
2323
_ "net/http/pprof"
24-
"os"
2524
"strconv"
2625
"sync"
2726
"time"
2827

2928
"github.com/prometheus/client_golang/prometheus"
3029
"github.com/prometheus/client_golang/prometheus/promhttp"
31-
"github.com/prometheus/common/promlog"
32-
"github.com/prometheus/exporter-toolkit/web"
3330
"github.com/sirupsen/logrus"
3431
"go.mongodb.org/mongo-driver/mongo"
3532

@@ -38,12 +35,10 @@ import (
3835

3936
// Exporter holds Exporter methods and attributes.
4037
type Exporter struct {
41-
path string
4238
client *mongo.Client
4339
clientMu sync.Mutex
4440
logger *logrus.Logger
4541
opts *Opts
46-
webListenAddress string
4742
lock *sync.Mutex
4843
totalCollectionsCount int
4944
}
@@ -56,10 +51,12 @@ type Opts struct {
5651
CollStatsLimit int
5752
CompatibleMode bool
5853
DirectConnect bool
54+
ConnectTimeoutMS int
5955
DisableDefaultRegistry bool
6056
DiscoveringMode bool
6157
GlobalConnPool bool
6258
ProfileTimeTS int
59+
TimeoutOffset int
6360

6461
CollectAll bool
6562
EnableDBStats bool
@@ -76,10 +73,8 @@ type Opts struct {
7673

7774
IndexStatsCollections []string
7875
Logger *logrus.Logger
79-
Path string
80-
URI string
81-
WebListenAddress string
82-
TLSConfigPath string
76+
77+
URI string
8378
}
8479

8580
var (
@@ -103,16 +98,9 @@ func New(opts *Opts) *Exporter {
10398

10499
ctx := context.Background()
105100

106-
if opts.Path == "" {
107-
opts.Logger.Warn("Web telemetry path \"\" invalid, falling back to \"/\" instead")
108-
opts.Path = "/"
109-
}
110-
111101
exp := &Exporter{
112-
path: opts.Path,
113102
logger: opts.Logger,
114103
opts: opts,
115-
webListenAddress: opts.WebListenAddress,
116104
lock: &sync.Mutex{},
117105
totalCollectionsCount: -1, // Not calculated yet. waiting the db connection.
118106
}
@@ -257,7 +245,7 @@ func (e *Exporter) getClient(ctx context.Context) (*mongo.Client, error) {
257245
return e.client, nil
258246
}
259247

260-
client, err := connect(context.Background(), e.opts.URI, e.opts.DirectConnect)
248+
client, err := connect(context.Background(), e.opts)
261249
if err != nil {
262250
return nil, err
263251
}
@@ -267,7 +255,7 @@ func (e *Exporter) getClient(ctx context.Context) (*mongo.Client, error) {
267255
}
268256

269257
// !e.opts.GlobalConnPool: create new client for every scrape.
270-
client, err := connect(ctx, e.opts.URI, e.opts.DirectConnect)
258+
client, err := connect(ctx, e.opts)
271259
if err != nil {
272260
return nil, err
273261
}
@@ -284,6 +272,7 @@ func (e *Exporter) Handler() http.Handler {
284272
if err != nil {
285273
seconds = 10
286274
}
275+
seconds -= e.opts.TimeoutOffset
287276

288277
var client *mongo.Client
289278
ctx, cancel := context.WithTimeout(r.Context(), time.Duration(seconds)*time.Second)
@@ -350,14 +339,15 @@ func (e *Exporter) Handler() http.Handler {
350339
gatherers = append(gatherers, prometheus.DefaultGatherer)
351340
}
352341

342+
var ti *topologyInfo
353343
if client != nil {
354344
// Topology can change between requests, so we need to get it every time.
355-
ti := newTopologyInfo(ctx, client, e.logger)
356-
357-
registry := e.makeRegistry(ctx, client, ti, requestOpts)
358-
gatherers = append(gatherers, registry)
345+
ti = newTopologyInfo(ctx, client, e.logger)
359346
}
360347

348+
registry := e.makeRegistry(ctx, client, ti, requestOpts)
349+
gatherers = append(gatherers, registry)
350+
361351
// Delegate http serving to Prometheus client library, which will call collector.Collect.
362352
h := promhttp.HandlerFor(gatherers, promhttp.HandlerOpts{
363353
ErrorHandling: promhttp.ContinueOnError,
@@ -368,41 +358,21 @@ func (e *Exporter) Handler() http.Handler {
368358
})
369359
}
370360

371-
// Run starts the exporter.
372-
func (e *Exporter) Run() {
373-
mux := http.DefaultServeMux
374-
mux.Handle(e.path, e.Handler())
375-
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
376-
w.Write([]byte(`<html>
377-
<head><title>MongoDB Exporter</title></head>
378-
<body>
379-
<h1>MongoDB Exporter</h1>
380-
<p><a href='/metrics'>Metrics</a></p>
381-
</body>
382-
</html>`))
383-
})
384-
385-
server := &http.Server{
386-
Handler: mux,
387-
}
388-
flags := &web.FlagConfig{
389-
WebListenAddresses: &[]string{e.webListenAddress},
390-
WebConfigFile: &e.opts.TLSConfigPath,
391-
}
392-
if err := web.ListenAndServe(server, flags, promlog.New(&promlog.Config{})); err != nil {
393-
e.logger.Errorf("error starting server: %v", err)
394-
os.Exit(1)
395-
}
396-
}
397-
398-
func connect(ctx context.Context, dsn string, directConnect bool) (*mongo.Client, error) {
399-
clientOpts, err := dsn_fix.ClientOptionsForDSN(dsn)
361+
func connect(ctx context.Context, opts *Opts) (*mongo.Client, error) {
362+
clientOpts, err := dsn_fix.ClientOptionsForDSN(opts.URI)
400363
if err != nil {
401364
return nil, fmt.Errorf("invalid dsn: %w", err)
402365
}
403-
clientOpts.SetDirect(directConnect)
366+
367+
clientOpts.SetDirect(opts.DirectConnect)
404368
clientOpts.SetAppName("mongodb_exporter")
405369

370+
if clientOpts.ConnectTimeout == nil {
371+
connectTimeout := time.Duration(opts.ConnectTimeoutMS) * time.Millisecond
372+
clientOpts.SetConnectTimeout(connectTimeout)
373+
clientOpts.SetServerSelectionTimeout(connectTimeout)
374+
}
375+
406376
client, err := mongo.Connect(ctx, clientOpts)
407377
if err != nil {
408378
return nil, fmt.Errorf("invalid MongoDB options: %w", err)

0 commit comments

Comments
 (0)