harness-drone/metric/sink/datadog.go

173 lines
3.7 KiB
Go
Raw Permalink Normal View History

2020-02-07 16:45:48 +00:00
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2019-03-05 07:16:53 +00:00
package sink
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/drone/drone/core"
)
type payload struct {
Series []series `json:"series"`
}
type series struct {
2019-03-13 21:47:47 +00:00
Metric string `json:"metric"`
Points [][]int64 `json:"points"`
Host string `json:"host"`
Type string `json:"type"`
Tags []string `json:"tags,omitempty"`
2019-03-05 07:16:53 +00:00
}
// Datadog defines a no-op sink to datadog.
type Datadog struct {
users core.UserStore
repos core.RepositoryStore
builds core.BuildStore
system core.System
config Config
client *http.Client
}
// New returns a Datadog sink.
func New(
users core.UserStore,
repos core.RepositoryStore,
builds core.BuildStore,
system core.System,
config Config,
) *Datadog {
return &Datadog{
users: users,
repos: repos,
builds: builds,
system: system,
config: config,
}
}
// Start starts the sink.
func (d *Datadog) Start(ctx context.Context) error {
for {
diff := midnightDiff()
select {
case <-time.After(diff):
d.do(ctx, time.Now().Unix())
case <-ctx.Done():
return nil
}
}
}
func (d *Datadog) do(ctx context.Context, unix int64) error {
users, err := d.users.Count(ctx)
if err != nil {
return err
}
repos, err := d.repos.Count(ctx)
if err != nil {
return err
}
builds, err := d.builds.Count(ctx)
if err != nil {
return err
}
2021-05-13 17:51:22 +00:00
userList, _ := d.users.ListRange(ctx, core.UserParams{
Sort: false,
Page: 0,
2021-05-13 17:51:22 +00:00
Size: 5,
})
2019-03-13 21:47:47 +00:00
tags := createTags(d.config)
2019-03-05 07:16:53 +00:00
data := new(payload)
data.Series = []series{
{
Metric: "drone.users",
Points: [][]int64{[]int64{unix, users}},
Type: "gauge",
Host: d.system.Host,
2021-05-13 17:51:22 +00:00
Tags: append(tags, createInstallerTags(userList)...),
2019-03-05 07:16:53 +00:00
},
{
Metric: "drone.repos",
Points: [][]int64{[]int64{unix, repos}},
Type: "gauge",
Host: d.system.Host,
2019-03-13 21:47:47 +00:00
Tags: tags,
2019-03-05 07:16:53 +00:00
},
{
Metric: "drone.builds",
Points: [][]int64{[]int64{unix, builds}},
Type: "gauge",
Host: d.system.Host,
2019-03-13 21:47:47 +00:00
Tags: tags,
2019-03-05 07:16:53 +00:00
},
}
buf := new(bytes.Buffer)
err = json.NewEncoder(buf).Encode(data)
if err != nil {
return err
}
endpoint := fmt.Sprintf("%s?api_key=%s", d.config.Endpoint, d.config.Token)
req, err := http.NewRequest("POST", endpoint, buf)
if err != nil {
return err
}
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
res, err := httpClient.Do(req)
if err != nil {
return err
}
res.Body.Close()
return nil
}
// Client returns the http client. If no custom
// client is provided, the default client is used.
func (d *Datadog) Client() *http.Client {
if d.client == nil {
return httpClient
}
return d.client
}
2019-11-10 15:38:03 +00:00
// calculate the differences between now and midnight.
2019-03-05 07:16:53 +00:00
func midnightDiff() time.Duration {
a := time.Now()
b := time.Date(a.Year(), a.Month(), a.Day()+1, 0, 0, 0, 0, a.Location())
return b.Sub(a)
}
// httpClient should be used for HTTP requests. It
// is configured with a timeout for reliability.
var httpClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: 30 * time.Second,
DisableKeepAlives: true,
},
Timeout: 1 * time.Minute,
}