Skip to content

Commit

Permalink
Merge pull request #782 from SiaFoundation/chris/metrics-timestamp
Browse files Browse the repository at this point in the history
Make sure all endpoints return RFC3339 formatted UTC timestamps
  • Loading branch information
ChrisSchinnerl authored Dec 5, 2023
2 parents 3ec628f + 0936817 commit 4289312
Show file tree
Hide file tree
Showing 26 changed files with 109 additions and 94 deletions.
3 changes: 1 addition & 2 deletions api/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"strings"
"time"

"go.sia.tech/core/types"
"go.sia.tech/renterd/hostdb"
Expand Down Expand Up @@ -92,7 +91,7 @@ type (
ScanningLastStart TimeRFC3339 `json:"scanningLastStart"`
UptimeMS DurationMS `json:"uptimeMS"`

StartTime time.Time `json:"startTime"`
StartTime TimeRFC3339 `json:"startTime"`
BuildState
}
)
Expand Down
3 changes: 1 addition & 2 deletions api/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package api

import (
"errors"
"time"
)

const (
Expand All @@ -25,7 +24,7 @@ var (

type (
Bucket struct {
CreatedAt time.Time `json:"createdAt"`
CreatedAt TimeRFC3339 `json:"createdAt"`
Name string `json:"name"`
Policy BucketPolicy `json:"policy"`
}
Expand Down
10 changes: 4 additions & 6 deletions api/bus.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package api

import (
"time"

"go.sia.tech/core/types"
)

type (
// ConsensusState holds the current blockheight and whether we are synced or not.
ConsensusState struct {
BlockHeight uint64 `json:"blockHeight"`
LastBlockTime time.Time `json:"lastBlockTime"`
Synced bool `json:"synced"`
BlockHeight uint64 `json:"blockHeight"`
LastBlockTime TimeRFC3339 `json:"lastBlockTime"`
Synced bool `json:"synced"`
}

// ConsensusNetwork holds the name of the network.
Expand Down Expand Up @@ -42,7 +40,7 @@ type (
type (
// BusStateResponse is the response type for the /bus/state endpoint.
BusStateResponse struct {
StartTime time.Time `json:"startTime"`
StartTime TimeRFC3339 `json:"startTime"`
BuildState
}
)
3 changes: 1 addition & 2 deletions api/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"net/url"
"time"

"go.sia.tech/core/types"
"go.sia.tech/renterd/hostdb"
Expand Down Expand Up @@ -76,7 +75,7 @@ type (
Limit int
}
HostsForScanningOptions struct {
MaxLastScan time.Time
MaxLastScan TimeRFC3339
Limit int
Offset int
}
Expand Down
14 changes: 7 additions & 7 deletions api/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ const (

type (
ContractSetMetric struct {
Contracts int `json:"contracts"`
Name string `json:"name"`
Timestamp time.Time `json:"timestamp"`
Contracts int `json:"contracts"`
Name string `json:"name"`
Timestamp TimeRFC3339 `json:"timestamp"`
}

ContractSetMetricsQueryOpts struct {
Expand All @@ -32,7 +32,7 @@ type (
ContractID types.FileContractID `json:"contractID"`
Name string `json:"name"`
Reason string `json:"reason,omitempty"`
Timestamp time.Time `json:"timestamp"`
Timestamp TimeRFC3339 `json:"timestamp"`
}

ContractSetChurnMetricsQueryOpts struct {
Expand All @@ -46,7 +46,7 @@ type (
HostKey types.PublicKey `json:"hostKey"`
Origin string `json:"origin"`
Duration time.Duration `json:"duration"`
Timestamp time.Time `json:"timestamp"`
Timestamp TimeRFC3339 `json:"timestamp"`
}

PerformanceMetricsQueryOpts struct {
Expand All @@ -56,7 +56,7 @@ type (
}

ContractMetric struct {
Timestamp time.Time `json:"timestamp"`
Timestamp TimeRFC3339 `json:"timestamp"`

ContractID types.FileContractID `json:"contractID"`
HostKey types.PublicKey `json:"hostKey"`
Expand All @@ -78,7 +78,7 @@ type (
}

WalletMetric struct {
Timestamp time.Time `json:"timestamp"`
Timestamp TimeRFC3339 `json:"timestamp"`

Confirmed types.Currency `json:"confirmed"`
Spendable types.Currency `json:"spendable"`
Expand Down
11 changes: 5 additions & 6 deletions api/multipart.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package api

import (
"errors"
"time"

"go.sia.tech/renterd/object"
)
Expand Down Expand Up @@ -31,14 +30,14 @@ type (
Key object.EncryptionKey `json:"key"`
Path string `json:"path"`
UploadID string `json:"uploadID"`
CreatedAt time.Time `json:"createdAt"`
CreatedAt TimeRFC3339 `json:"createdAt"`
}

MultipartListPartItem struct {
PartNumber int `json:"partNumber"`
LastModified time.Time `json:"lastModified"`
ETag string `json:"eTag"`
Size int64 `json:"size"`
PartNumber int `json:"partNumber"`
LastModified TimeRFC3339 `json:"lastModified"`
ETag string `json:"eTag"`
Size int64 `json:"size"`
}

MultipartCompletedPart struct {
Expand Down
15 changes: 7 additions & 8 deletions api/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"net/url"
"path/filepath"
"strings"
"time"

"go.sia.tech/renterd/object"
)
Expand Down Expand Up @@ -51,12 +50,12 @@ type (

// ObjectMetadata contains various metadata about an object.
ObjectMetadata struct {
ETag string `json:"eTag,omitempty"`
Health float64 `json:"health"`
MimeType string `json:"mimeType,omitempty"`
ModTime time.Time `json:"modTime"`
Name string `json:"name"`
Size int64 `json:"size"`
ETag string `json:"eTag,omitempty"`
Health float64 `json:"health"`
MimeType string `json:"mimeType,omitempty"`
ModTime TimeRFC3339 `json:"modTime"`
Name string `json:"name"`
Size int64 `json:"size"`
}

// ObjectAddRequest is the request type for the /bus/object/*key endpoint.
Expand Down Expand Up @@ -125,7 +124,7 @@ type (
// LastModified returns the object's ModTime formatted for use in the
// 'Last-Modified' header
func (o ObjectMetadata) LastModified() string {
return o.ModTime.UTC().Format(http.TimeFormat)
return o.ModTime.Std().Format(http.TimeFormat)
}

// ContentType returns the object's MimeType for use in the 'Content-Type'
Expand Down
31 changes: 28 additions & 3 deletions api/param.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,40 @@ func (s *ParamString) UnmarshalText(b []byte) error {
return nil
}

// CompareTimeRFC3339 is a comparer function to be used with cmp.Comparer.
func CompareTimeRFC3339(t1, t2 TimeRFC3339) bool {
return time.Time(t1).UTC().Equal(time.Time(t2).UTC())
}

// TimeNow returns the current time as a TimeRFC3339.
func TimeNow() TimeRFC3339 {
return TimeRFC3339(time.Now())
}

// Std converts a TimeRFC3339 to a time.Time.
func (t TimeRFC3339) Std() time.Time { return time.Time(t).UTC() }

// IsZero reports whether t represents the zero time instant, January 1, year 1,
// 00:00:00 UTC.
func (t TimeRFC3339) IsZero() bool { return (time.Time)(t).IsZero() }

// String implements fmt.Stringer.
func (t TimeRFC3339) String() string { return (time.Time)(t).Format(time.RFC3339Nano) }
func (t TimeRFC3339) String() string { return (time.Time)(t).UTC().Format(time.RFC3339Nano) }

// UnmarshalText implements encoding.TextUnmarshaler.
func (t *TimeRFC3339) UnmarshalText(b []byte) error { return (*time.Time)(t).UnmarshalText(b) }
func (t *TimeRFC3339) UnmarshalText(b []byte) error {
var stdTime time.Time
err := stdTime.UnmarshalText(b)
if err != nil {
return err
}
*t = TimeRFC3339(stdTime.UTC())
return nil
}

// MarshalJSON implements json.Marshaler.
func (t TimeRFC3339) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%s"`, (time.Time)(t).Format(time.RFC3339))), nil
return []byte(fmt.Sprintf(`"%s"`, (time.Time)(t).UTC().Format(time.RFC3339))), nil
}

// String implements fmt.Stringer.
Expand Down
12 changes: 5 additions & 7 deletions api/state.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package api

import "time"

type (
// BuildState contains static information about the build.
BuildState struct {
Network string `json:"network"`
Version string `json:"version"`
Commit string `json:"commit"`
OS string `json:"OS"`
BuildTime time.Time `json:"buildTime"`
Network string `json:"network"`
Version string `json:"version"`
Commit string `json:"commit"`
OS string `json:"OS"`
BuildTime TimeRFC3339 `json:"buildTime"`
}
)
7 changes: 3 additions & 4 deletions api/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"io"
"strconv"
"strings"
"time"

rhpv2 "go.sia.tech/core/rhp/v2"
rhpv3 "go.sia.tech/core/rhp/v3"
Expand Down Expand Up @@ -204,8 +203,8 @@ type (

// WorkerStateResponse is the response type for the /worker/state endpoint.
WorkerStateResponse struct {
ID string `json:"id"`
StartTime time.Time `json:"startTime"`
ID string `json:"id"`
StartTime TimeRFC3339 `json:"startTime"`
BuildState
}

Expand All @@ -220,7 +219,7 @@ type (
GetObjectResponse struct {
Content io.ReadCloser `json:"content"`
ContentType string `json:"contentType"`
ModTime time.Time `json:"modTime"`
ModTime TimeRFC3339 `json:"modTime"`
Range *DownloadRange `json:"range,omitempty"`
Size int64 `json:"size"`
}
Expand Down
4 changes: 2 additions & 2 deletions autopilot/autopilot.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,13 +654,13 @@ func (ap *Autopilot) stateHandlerGET(jc jape.Context) {
ScanningLastStart: api.TimeRFC3339(sLastStart),
UptimeMS: api.DurationMS(ap.Uptime()),

StartTime: ap.StartTime(),
StartTime: api.TimeRFC3339(ap.StartTime()),
BuildState: api.BuildState{
Network: build.NetworkName(),
Version: build.Version(),
Commit: build.Commit(),
OS: runtime.GOOS,
BuildTime: build.BuildTime(),
BuildTime: api.TimeRFC3339(build.BuildTime()),
},
})
}
Expand Down
2 changes: 1 addition & 1 deletion autopilot/contractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ func (c *contractor) computeContractSetChanged(ctx context.Context, name string,
}

// record churn metrics
now := time.Now()
now := api.TimeNow()
var metrics []api.ContractSetChurnMetric
for _, fcid := range added {
metrics = append(metrics, api.ContractSetChurnMetric{
Expand Down
2 changes: 1 addition & 1 deletion autopilot/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func (s *scanner) launchHostScans() chan scanReq {
for !s.ap.isStopped() && !exhausted {
// fetch next batch
hosts, err := s.bus.HostsForScanning(context.Background(), api.HostsForScanningOptions{
MaxLastScan: cutoff,
MaxLastScan: api.TimeRFC3339(cutoff),
Offset: offset,
Limit: int(s.scanBatchSize),
})
Expand Down
6 changes: 3 additions & 3 deletions bus/bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,7 @@ func (b *bus) paramsHandlerUploadGET(jc jape.Context) {
func (b *bus) consensusState() api.ConsensusState {
return api.ConsensusState{
BlockHeight: b.cm.TipState().Index.Height,
LastBlockTime: b.cm.LastBlockTime(),
LastBlockTime: api.TimeRFC3339(b.cm.LastBlockTime()),
Synced: b.cm.Synced(),
}
}
Expand Down Expand Up @@ -1911,13 +1911,13 @@ func (b *bus) contractTaxHandlerGET(jc jape.Context) {

func (b *bus) stateHandlerGET(jc jape.Context) {
jc.Encode(api.BusStateResponse{
StartTime: b.startTime,
StartTime: api.TimeRFC3339(b.startTime),
BuildState: api.BuildState{
Network: build.NetworkName(),
Version: build.Version(),
Commit: build.Commit(),
OS: runtime.GOOS,
BuildTime: build.BuildTime(),
BuildTime: api.TimeRFC3339(build.BuildTime()),
},
})
}
Expand Down
10 changes: 5 additions & 5 deletions internal/testing/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,10 @@ func TestObjectEntries(t *testing.T) {
assertMetadata := func(entries []api.ObjectMetadata) {
for i := range entries {
// assert mod time
if !strings.HasSuffix(entries[i].Name, "/") && !entries[i].ModTime.After(start.UTC()) {
if !strings.HasSuffix(entries[i].Name, "/") && !entries[i].ModTime.Std().After(start.UTC()) {
t.Fatal("mod time should be set")
}
entries[i].ModTime = time.Time{}
entries[i].ModTime = api.TimeRFC3339{}

// assert mime type
if entries[i].MimeType == "" {
Expand Down Expand Up @@ -2208,7 +2208,7 @@ func TestBusRecordedMetrics(t *testing.T) {
t.Fatalf("expected 1 contract, got %v", m.Contracts)
} else if m.Name != testContractSet {
t.Fatalf("expected contract set %v, got %v", testContractSet, m.Name)
} else if !m.Timestamp.After(startTime) {
} else if !m.Timestamp.Std().After(startTime) {
t.Fatal("expected time to be after start time")
}
}
Expand All @@ -2225,7 +2225,7 @@ func TestBusRecordedMetrics(t *testing.T) {
t.Fatal("expected non-zero FCID")
} else if m.Name != testContractSet {
t.Fatalf("expected contract set %v, got %v", testContractSet, m.Name)
} else if !m.Timestamp.After(startTime) {
} else if !m.Timestamp.Std().After(startTime) {
t.Fatal("expected time to be after start time")
}

Expand All @@ -2243,7 +2243,7 @@ func TestBusRecordedMetrics(t *testing.T) {

if len(cMetrics) != 1 {
t.Fatalf("expected 1 metric, got %v", len(cMetrics))
} else if m := cMetrics[0]; !startTime.Before(m.Timestamp) {
} else if m := cMetrics[0]; !startTime.Before(m.Timestamp.Std()) {
t.Fatalf("expected time to be after start time, got %v", m.Timestamp)
} else if m.ContractID == (types.FileContractID{}) {
t.Fatal("expected non-zero FCID")
Expand Down
Loading

0 comments on commit 4289312

Please sign in to comment.