Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d4d655a
Rewrite stats_summary from Perl to Golang
mhoppa Nov 19, 2019
a1c5af0
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Nov 19, 2019
4c0003f
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Nov 21, 2019
9dfe359
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Nov 21, 2019
483c89d
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Dec 2, 2019
0502362
Add API tests
mhoppa Dec 3, 2019
1b9ad17
Update Changelog
mhoppa Dec 3, 2019
16136d6
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Dec 3, 2019
c17be61
Update traffic_stats.go
mhoppa Dec 3, 2019
403d912
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Dec 3, 2019
2668b21
Merge conflict
mhoppa Dec 3, 2019
0600dc8
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Dec 4, 2019
051f1a0
Merge branch 'master' into feature/rewrite_stats_summary
mhoppa Dec 5, 2019
6a83b27
Address comments
mhoppa Dec 5, 2019
da27ab5
Add POST Summary stats
mhoppa Dec 6, 2019
89e77d7
Merge remote-tracking branch 'remote/master' into feature/rewrite_sta…
mhoppa Jan 6, 2020
cf06e36
Move stats_summary POST to 1.5
mhoppa Jan 6, 2020
0353348
Merge branch 'master' into feature/rewrite_stats_summary_post
mhoppa Jan 9, 2020
a7342d5
Merge branch 'master' into feature/rewrite_stats_summary_post
mhoppa Jan 10, 2020
df86ac9
Fix docs issues
mhoppa Jan 10, 2020
997b75b
Merge branch 'master' into feature/rewrite_stats_summary_post
mhoppa Jan 14, 2020
4ece636
Actually adress comments for docs
mhoppa Jan 14, 2020
ebafda9
Merge branch 'master' into feature/rewrite_stats_summary_post
mhoppa Jan 29, 2020
171d029
Update changelog
mhoppa Jan 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Traffic Ops Golang Endpoints
- /api/1.1/cachegroupparameters/{{cachegroupID}}/{{parameterID}} `(DELETE)`
- /api/1.5/to_extensions `(POST)`
- /api/1.5/stats_summary `(POST)`
Comment thread
ocket8888 marked this conversation as resolved.

### Changed

Expand Down
77 changes: 76 additions & 1 deletion docs/source/api/stats_summary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ Summary Stats
"""""""""""""

:cdnName: The CDN name for which the summary stat was taken for

.. note:: If the ``cdn`` is equal to ``all`` it represents summary_stats across all delivery services across all CDNs

:deliveryServiceName: The :term:`Delivery Service` display name for which the summary stat was taken for

.. note:: If the ``deliveryServiceName`` is equal to ``all`` it represents summary_stats across all delivery services within the given CDN
Expand Down Expand Up @@ -173,4 +176,76 @@ Last Updated Summary Stat

{ "response": {
"summaryTime": "2019-11-19 00:04:06+00"
}}
}}

``POST``
Comment thread
ocket8888 marked this conversation as resolved.
========

.. versionadded:: 1.5

Post a stats summary for a given stat.

:Auth. Required: Yes
:Roles Required: None
:Response Type: Object

Request Structure
-----------------
:cdnName: The CDN name for which the summary stat was taken for

.. note:: If the ``cdn`` is equal to ``all`` it represents summary_stats across all delivery services across all CDNs

:deliveryServiceName: The :term:`Delivery Service` display name for which the summary stat was taken for

.. note:: If the ``deliveryServiceName`` is equal to ``all`` it represents summary_stats across all delivery services within the given CDN

:statName: Stat name summary stat represents
:statValue: Summary stat value
:summaryTime: Timestamp of summary, in an ISO-like format
:statDate: Date stat was taken, in :rfc:`3339` format

.. note:: ``statName``, ``statValue`` and ``summaryTime`` are required. If ``cdnName`` and ``deliveryServiceName`` are not given they will default to ``all``.

.. code-block:: http
:caption: Request Example

POST /api/1.5/stats_summary HTTP/1.1
Host: trafficops.infra.ciab.test
User-Agent: curl/7.47.0
Accept: */*
Cookie: mojolicious=...
Content-Length: 113
Content-Type: application/json

{
"cdnName": "CDN-in-a-Box",
"deliveryServiceName": "all",
"statName": "daily_maxgbps",
"statValue": 10,
"summaryTime": "2019-12-05 00:03:57+00",
"statDate": "2019-12-05"
}

Response Structure
------------------
.. code-block:: http
:caption: Response Example

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Access-Control-Allow-Origin: *
Content-Type: application/json
Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly
Whole-Content-Sha512: ezxk+iP7o7KE7zpWmGc0j8nz5k+1wAzY0HiNiA2xswTQrt+N+6CgQqUV2r9G1HAsPNr0HF2PhYs/Xr7DrYOw0A==
X-Server-Name: traffic_ops_golang/
Date: Thu, 06 Dec 2018 02:14:45 GMT
Content-Length: 97

{ "alerts": [
{
"text": "Stats Summary was successfully created",
"level": "success"
}]
}
44 changes: 33 additions & 11 deletions lib/go-tc/stats_summary.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package tc

import (
"database/sql"
"encoding/json"
"errors"
"time"

"github.com/apache/trafficcontrol/lib/go-tc/tovalidate"
"github.com/apache/trafficcontrol/lib/go-util"
validation "github.com/go-ozzo/ozzo-validation"
)

/*
Expand Down Expand Up @@ -35,15 +39,22 @@ type StatsSummaryResponse struct {

// StatsSummary ...
type StatsSummary struct {
ID int `json:"-" db:"id"`
CDNName string `json:"cdnName" db:"cdn_name"`
DeliveryService string `json:"deliveryServiceName" db:"deliveryservice_name"`
StatName string `json:"statName" db:"stat_name"`
StatValue float64 `json:"statValue" db:"stat_value"`
CDNName *string `json:"cdnName" db:"cdn_name"`
DeliveryService *string `json:"deliveryServiceName" db:"deliveryservice_name"`
StatName *string `json:"statName" db:"stat_name"`
StatValue *float64 `json:"statValue" db:"stat_value"`
SummaryTime time.Time `json:"summaryTime" db:"summary_time"`
StatDate *time.Time `json:"statDate" db:"stat_date"`
}

func (ss StatsSummary) Validate(tx *sql.Tx) error {
errs := tovalidate.ToErrors(validation.Errors{
"statName": validation.Validate(ss.StatName, validation.Required),
"statValue": validation.Validate(ss.StatValue, validation.Required),
})
return util.JoinErrs(errs)
}

// UnmarshalJSON Customized Unmarshal to force date format on statDate
func (ss *StatsSummary) UnmarshalJSON(data []byte) error {
type Alias StatsSummary
Expand All @@ -59,19 +70,30 @@ func (ss *StatsSummary) UnmarshalJSON(data []byte) error {
return err
}
if resp.StatDate != nil {
statDate, err := time.Parse(dateFormat, *resp.StatDate)
statDate, err := parseTime(*resp.StatDate)
if err != nil {
return err
return errors.New("invalid timestamp given for statDate")
}
ss.StatDate = &statDate
}

ss.SummaryTime, err = time.Parse(time.RFC3339, resp.SummaryTime)
ss.SummaryTime, err = parseTime(resp.SummaryTime)
if err != nil {
return errors.New("invalid timestamp given for summaryTime")
}
return nil
}

func parseTime(ts string) (time.Time, error) {
rt, err := time.Parse(time.RFC3339, ts)
if err == nil {
return rt, err
}
rt, err = time.Parse(TimeLayout, ts)
if err == nil {
return nil
return rt, err
}
ss.SummaryTime, err = time.Parse(TimeLayout, resp.SummaryTime)
return err
return time.Parse(dateFormat, ts)
}

// MarshalJSON Customized Marshal to force date format on statDate
Expand Down
2 changes: 1 addition & 1 deletion traffic_ops/client/stats_summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ func (to *Session) CreateSummaryStats(statsSummary tc.StatsSummary) (tc.Alerts,
if err != nil {
return tc.Alerts{}, reqInf, err
}
reqInf, err = post(to, fmt.Sprintf("%s/%s", basePathSummaryStats, "create"), reqBody, &alerts)
reqInf, err = post(to, basePathSummaryStats, reqBody, &alerts)
Comment thread
ocket8888 marked this conversation as resolved.
return alerts, reqInf, err
}
11 changes: 5 additions & 6 deletions traffic_ops/testing/api/v1/stats_summary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func GetTestStatsSummaries(t *testing.T) {
expectedStatsSummaries: func() []tc.StatsSummary {
statsSummaries := []tc.StatsSummary{}
for _, ss := range testStatsSummaries {
if ss.StatName == "daily_bytesserved" {
if *ss.StatName == "daily_bytesserved" {
statsSummaries = append(statsSummaries, ss)
}
}
Expand Down Expand Up @@ -113,13 +113,13 @@ func GetTestStatsSummaries(t *testing.T) {
for _, ess := range tc.expectedStatsSummaries {
found := false
for _, ss := range tsr.Response {
if ess.StatName == ss.StatName && ess.SummaryTime.Equal(ss.SummaryTime) {
if *ess.StatName == *ss.StatName && ess.SummaryTime.Equal(ss.SummaryTime) {
found = true
break
}
}
if !found {
t.Errorf("expected to find stat %v in stats summary response", ess.StatName)
t.Errorf("expected to find stat %v in stats summary response", *ess.StatName)
}
}
})
Expand Down Expand Up @@ -150,8 +150,8 @@ func GetTestStatsSummariesLastUpdated(t *testing.T) {
}
for _, ss := range testStatsSummaries {
testCases = append(testCases, testCase{
description: fmt.Sprintf("latest updated timestamp for - %v", ss.StatName),
stat: util.StrPtr(ss.StatName),
description: fmt.Sprintf("latest updated timestamp for - %v", *ss.StatName),
stat: ss.StatName,
errExpected: false,
expectedTimestamp: ss.SummaryTime,
})
Expand All @@ -175,5 +175,4 @@ func GetTestStatsSummariesLastUpdated(t *testing.T) {
}
})
}

}
1 change: 1 addition & 0 deletions traffic_ops/traffic_ops_golang/routing/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) {

// Stats Summary
{1.1, http.MethodGet, `stats_summary/?(\.json)?$`, trafficstats.GetStatsSummary, auth.PrivLevelReadOnly, Authenticated, nil, 380498598, perlBypass},
{1.5, http.MethodPost, `stats_summary/?(\.json)?$`, trafficstats.CreateStatsSummary, auth.PrivLevelReadOnly, Authenticated, nil, 380491598, noPerlBypass},

// TO Extensions
{1.5, http.MethodPost, `to_extensions$`, toextension.CreateTOExtension, auth.PrivLevelReadOnly, Authenticated, nil, 380498599, noPerlBypass},
Expand Down
68 changes: 67 additions & 1 deletion traffic_ops/traffic_ops_golang/trafficstats/stats_summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,56 @@ func queryStatsSummary(tx *sqlx.Tx, q string, queryValues map[string]interface{}
return statsSummaries, nil
}

// CreateStatsSummary handler for creating stats summaries
func CreateStatsSummary(w http.ResponseWriter, r *http.Request) {
inf, userErr, sysErr, errCode := api.NewInfo(r, []string{}, []string{})
if userErr != nil || sysErr != nil {
api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
return
}
defer inf.Close()

ss := tc.StatsSummary{}

if err := api.Parse(r.Body, inf.Tx.Tx, &ss); err != nil {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, err, nil)
return
}

// CDN Name and Delivery service name are defaulted to "all" if not defined
if ss.CDNName == nil || len(*ss.CDNName) == 0 {
ss.CDNName = util.StrPtr("all")
}

if ss.DeliveryService == nil || len(*ss.DeliveryService) == 0 {
ss.DeliveryService = util.StrPtr("all")
}

id := -1
rows, err := inf.Tx.NamedQuery(insertQuery(), &ss)
if err != nil {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("inserting stats summary: %v", err))
return
}
for rows.Next() {
if err := rows.Scan(&id); err != nil {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("scanning created stats summary id: %v", err))
return
}
}
if id == -1 {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("sstats summary id: %v", err))
return
}

successMsg := "Stats Summary was successfully created"
logMsg := fmt.Sprintf("STATSSUMMARY: %v, ID: %v, ACTION: create stats_summary", *ss.StatName, id)
api.CreateChangeLogRawTx(api.ApiChange, logMsg, inf.User, inf.Tx.Tx)
api.WriteRespAlert(w, r, tc.SuccessLevel, successMsg)
}

func selectQuery() string {
return `SELECT
id,
cdn_name,
deliveryservice_name,
stat_name,
Expand All @@ -122,3 +169,22 @@ summary_time,
stat_date
FROM stats_summary`
}

func insertQuery() string {
return `
INSERT INTO stats_summary (
cdn_name,
deliveryservice_name,
stat_name,
stat_value,
summary_time,
stat_date)
VALUES (
:cdn_name,
:deliveryservice_name,
:stat_name,
:stat_value,
:summary_time,
:stat_date) RETURNING id
`
}
16 changes: 8 additions & 8 deletions traffic_stats/traffic_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,10 +315,10 @@ func calcDailyMaxGbps(client influx.Client, bp influx.BatchPoints, startTime tim
statTime, _ := time.Parse(time.RFC3339, t)
log.Infof("max gbps for cdn %v = %v", cdn, value)
var statsSummary tc.StatsSummary
statsSummary.CDNName = cdn
statsSummary.DeliveryService = "all"
statsSummary.StatName = "daily_maxgbps"
statsSummary.StatValue = value
statsSummary.CDNName = util.StrPtr(cdn)
statsSummary.DeliveryService = util.StrPtr("all")
statsSummary.StatName = util.StrPtr("daily_maxgbps")
statsSummary.StatValue = util.FloatPtr(value)
statsSummary.SummaryTime = time.Now()
statsSummary.StatDate = &statTime
go writeSummaryStats(config, statsSummary)
Expand Down Expand Up @@ -375,10 +375,10 @@ func calcDailyBytesServed(client influx.Client, bp influx.BatchPoints, startTime
log.Infof("TBytes served for cdn %v = %v", cdn, bytesServedTB)
//write to Traffic Ops
var statsSummary tc.StatsSummary
statsSummary.CDNName = cdn
statsSummary.DeliveryService = "all"
statsSummary.StatName = "daily_bytesserved"
statsSummary.StatValue = bytesServedTB
statsSummary.CDNName = util.StrPtr(cdn)
statsSummary.DeliveryService = util.StrPtr("all")
statsSummary.StatName = util.StrPtr("daily_bytesserved")
statsSummary.StatValue = util.FloatPtr(bytesServedTB)
statsSummary.SummaryTime = time.Now()
statsSummary.StatDate = &startTime
go writeSummaryStats(config, statsSummary)
Expand Down