Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
248
plugins/inputs/mailchimp/chimp_api.go
Normal file
248
plugins/inputs/mailchimp/chimp_api.go
Normal file
|
@ -0,0 +1,248 @@
|
|||
package mailchimp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
)
|
||||
|
||||
const (
|
||||
reportsEndpoint string = "/3.0/reports"
|
||||
reportsEndpointCampaign string = "/3.0/reports/%s"
|
||||
)
|
||||
|
||||
var mailchimpDatacenter = regexp.MustCompile("[a-z]+[0-9]+$")
|
||||
|
||||
type chimpAPI struct {
|
||||
transport http.RoundTripper
|
||||
debug bool
|
||||
|
||||
sync.Mutex
|
||||
|
||||
url *url.URL
|
||||
log telegraf.Logger
|
||||
}
|
||||
|
||||
type reportsParams struct {
|
||||
count string
|
||||
offset string
|
||||
sinceSendTime string
|
||||
beforeSendTime string
|
||||
}
|
||||
|
||||
func (p *reportsParams) String() string {
|
||||
v := url.Values{}
|
||||
if p.count != "" {
|
||||
v.Set("count", p.count)
|
||||
}
|
||||
if p.offset != "" {
|
||||
v.Set("offset", p.offset)
|
||||
}
|
||||
if p.beforeSendTime != "" {
|
||||
v.Set("before_send_time", p.beforeSendTime)
|
||||
}
|
||||
if p.sinceSendTime != "" {
|
||||
v.Set("since_send_time", p.sinceSendTime)
|
||||
}
|
||||
return v.Encode()
|
||||
}
|
||||
|
||||
func newChimpAPI(apiKey string, log telegraf.Logger) *chimpAPI {
|
||||
u := &url.URL{}
|
||||
u.Scheme = "https"
|
||||
u.Host = mailchimpDatacenter.FindString(apiKey) + ".api.mailchimp.com"
|
||||
u.User = url.UserPassword("", apiKey)
|
||||
return &chimpAPI{url: u, log: log}
|
||||
}
|
||||
|
||||
type apiError struct {
|
||||
Status int `json:"status"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Detail string `json:"detail"`
|
||||
Instance string `json:"instance"`
|
||||
}
|
||||
|
||||
func (e apiError) Error() string {
|
||||
return fmt.Sprintf("ERROR %v: %v. See %v", e.Status, e.Title, e.Type)
|
||||
}
|
||||
|
||||
func chimpErrorCheck(body []byte) error {
|
||||
var e apiError
|
||||
if err := json.Unmarshal(body, &e); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.Title != "" || e.Status != 0 {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *chimpAPI) getReports(params reportsParams) (reportsResponse, error) {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
a.url.Path = reportsEndpoint
|
||||
|
||||
var response reportsResponse
|
||||
rawjson, err := a.runChimp(params)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawjson, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (a *chimpAPI) getReport(campaignID string) (report, error) {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
a.url.Path = fmt.Sprintf(reportsEndpointCampaign, campaignID)
|
||||
|
||||
var response report
|
||||
rawjson, err := a.runChimp(reportsParams{})
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawjson, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (a *chimpAPI) runChimp(params reportsParams) ([]byte, error) {
|
||||
client := &http.Client{
|
||||
Transport: a.transport,
|
||||
Timeout: 4 * time.Second,
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
req, err := http.NewRequest("GET", a.url.String(), &b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.URL.RawQuery = params.String()
|
||||
req.Header.Set("User-Agent", "Telegraf-MailChimp-Plugin")
|
||||
if a.debug {
|
||||
a.log.Debugf("request URL: %s", req.URL.String())
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
//nolint:errcheck // LimitReader returns io.EOF and we're not interested in read errors.
|
||||
body, _ := io.ReadAll(io.LimitReader(resp.Body, 200))
|
||||
return nil, fmt.Errorf("%s returned HTTP status %s: %q", a.url.String(), resp.Status, body)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a.debug {
|
||||
a.log.Debugf("response Body: %q", string(body))
|
||||
}
|
||||
|
||||
if err := chimpErrorCheck(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
type reportsResponse struct {
|
||||
Reports []report `json:"reports"`
|
||||
TotalItems int `json:"total_items"`
|
||||
}
|
||||
|
||||
type report struct {
|
||||
ID string `json:"id"`
|
||||
CampaignTitle string `json:"campaign_title"`
|
||||
Type string `json:"type"`
|
||||
EmailsSent int `json:"emails_sent"`
|
||||
AbuseReports int `json:"abuse_reports"`
|
||||
Unsubscribed int `json:"unsubscribed"`
|
||||
SendTime string `json:"send_time"`
|
||||
|
||||
TimeSeries []timeSeries
|
||||
Bounces bounces `json:"bounces"`
|
||||
Forwards forwards `json:"forwards"`
|
||||
Opens opens `json:"opens"`
|
||||
Clicks clicks `json:"clicks"`
|
||||
FacebookLikes facebookLikes `json:"facebook_likes"`
|
||||
IndustryStats industryStats `json:"industry_stats"`
|
||||
ListStats listStats `json:"list_stats"`
|
||||
}
|
||||
|
||||
type bounces struct {
|
||||
HardBounces int `json:"hard_bounces"`
|
||||
SoftBounces int `json:"soft_bounces"`
|
||||
SyntaxErrors int `json:"syntax_errors"`
|
||||
}
|
||||
|
||||
type forwards struct {
|
||||
ForwardsCount int `json:"forwards_count"`
|
||||
ForwardsOpens int `json:"forwards_opens"`
|
||||
}
|
||||
|
||||
type opens struct {
|
||||
OpensTotal int `json:"opens_total"`
|
||||
UniqueOpens int `json:"unique_opens"`
|
||||
OpenRate float64 `json:"open_rate"`
|
||||
LastOpen string `json:"last_open"`
|
||||
}
|
||||
|
||||
type clicks struct {
|
||||
ClicksTotal int `json:"clicks_total"`
|
||||
UniqueClicks int `json:"unique_clicks"`
|
||||
UniqueSubscriberClicks int `json:"unique_subscriber_clicks"`
|
||||
ClickRate float64 `json:"click_rate"`
|
||||
LastClick string `json:"last_click"`
|
||||
}
|
||||
|
||||
type facebookLikes struct {
|
||||
RecipientLikes int `json:"recipient_likes"`
|
||||
UniqueLikes int `json:"unique_likes"`
|
||||
FacebookLikes int `json:"facebook_likes"`
|
||||
}
|
||||
|
||||
type industryStats struct {
|
||||
Type string `json:"type"`
|
||||
OpenRate float64 `json:"open_rate"`
|
||||
ClickRate float64 `json:"click_rate"`
|
||||
BounceRate float64 `json:"bounce_rate"`
|
||||
UnopenRate float64 `json:"unopen_rate"`
|
||||
UnsubRate float64 `json:"unsub_rate"`
|
||||
AbuseRate float64 `json:"abuse_rate"`
|
||||
}
|
||||
|
||||
type listStats struct {
|
||||
SubRate float64 `json:"sub_rate"`
|
||||
UnsubRate float64 `json:"unsub_rate"`
|
||||
OpenRate float64 `json:"open_rate"`
|
||||
ClickRate float64 `json:"click_rate"`
|
||||
}
|
||||
|
||||
type timeSeries struct {
|
||||
TimeStamp string `json:"timestamp"`
|
||||
EmailsSent int `json:"emails_sent"`
|
||||
UniqueOpens int `json:"unique_opens"`
|
||||
RecipientsClick int `json:"recipients_click"`
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue