Skip to content

Commit

Permalink
GOCBC-688: Updated diagnostics to match latest RFC.
Browse files Browse the repository at this point in the history
Change-Id: I191b8e1dc4ec109b022f83abbaaca4a82ea4feb8
  • Loading branch information
brett19 committed Jan 17, 2020
1 parent ccf32ee commit cf84d51
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 235 deletions.
177 changes: 78 additions & 99 deletions bucket_ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,94 +9,73 @@ import (
"github.com/google/uuid"
)

// PingServiceEntry represents a single entry in a ping report.
type PingServiceEntry struct {
RemoteAddr string
State string
Latency time.Duration
Scope string
ID string
Detail string
// EndpointPingReport represents a single entry in a ping report.
type EndpointPingReport struct {
ID string
Local string
Remote string
State PingState
Error string
Namespace string
Latency time.Duration
}

// PingResult encapsulates the details from a executed ping operation.
type PingResult struct {
Services map[ServiceType][]PingServiceEntry
ConfigRev int64
ID string
ID string
Services map[ServiceType][]EndpointPingReport

sdk string
}

type jsonPingServiceEntry struct {
Remote string `json:"remote"`
LatencyUs uint64 `json:"latency_us"`
Scope string `json:"scope,omitempty"`
type jsonEndpointPingReport struct {
ID string `json:"id,omitempty"`
State string `json:"state"`
Detail string `json:"detail"`
Local string `json:"local,omitempty"`
Remote string `json:"remote,omitempty"`
State string `json:"state,omitempty"`
Error string `json:"error,omitempty"`
Namespace string `json:"namespace,omitempty"`
LatencyUs uint64 `json:"latency_us"`
}

type jsonPingReport struct {
Version int `json:"version"`
ID string `json:"id"`
Sdk string `json:"sdk"`
Services map[string][]jsonPingServiceEntry `json:"services"`
ConfigRev int64 `json:"config_rev"`
Version int `json:"version"`
SDK string `json:"sdk,omitempty"`
ID string `json:"id,omitempty"`
Services map[string][]jsonEndpointPingReport `json:"services,omitempty"`
}

// MarshalJSON generates a JSON representation of this ping report.
func (report *PingResult) MarshalJSON() ([]byte, error) {
jsonReport := jsonPingReport{
Version: 1,
Version: 2,
SDK: report.sdk,
ID: report.ID,
Sdk: Identifier() + " " + "gocbcore/" + gocbcore.Version(),
Services: make(map[string][]jsonPingServiceEntry),
Services: make(map[string][]jsonEndpointPingReport),
}

for key, serviceType := range report.Services {
serviceStr := diagServiceString(key)
for serviceType, serviceInfo := range report.Services {
serviceStr := serviceTypeToString(serviceType)
if _, ok := jsonReport.Services[serviceStr]; !ok {
jsonReport.Services[serviceStr] = make([]jsonPingServiceEntry, 0)
jsonReport.Services[serviceStr] = make([]jsonEndpointPingReport, 0)
}
for _, service := range serviceType {
jsonReport.Services[serviceStr] = append(jsonReport.Services[serviceStr], jsonPingServiceEntry{
Remote: service.RemoteAddr,
LatencyUs: uint64(service.Latency / time.Nanosecond),
State: service.State,
Scope: service.Scope,

for _, service := range serviceInfo {
jsonReport.Services[serviceStr] = append(jsonReport.Services[serviceStr], jsonEndpointPingReport{
ID: service.ID,
Detail: service.Detail,
Local: service.Local,
Remote: service.Remote,
State: pingStateToString(service.State),
Error: service.Error,
Namespace: service.Namespace,
LatencyUs: uint64(service.Latency / time.Nanosecond),
})
}
}

return json.Marshal(&jsonReport)
}

func (jsonReport *jsonPingReport) toReport() *PingResult {
report := &PingResult{
ID: jsonReport.ID,
}

for key, jsonServices := range jsonReport.Services {
serviceType := diagStringService(key)
if _, ok := report.Services[serviceType]; !ok {
report.Services[serviceType] = make([]PingServiceEntry, 0)
}
for _, jsonService := range jsonServices {
report.Services[serviceType] = append(report.Services[serviceType], PingServiceEntry{
RemoteAddr: jsonService.Remote,
Latency: time.Duration(jsonService.LatencyUs) * time.Nanosecond,
State: jsonService.State,
Scope: jsonService.Scope,
ID: jsonService.ID,
Detail: jsonService.Detail,
})
}
}

return report
}

func (b *Bucket) pingKv(provider kvProvider) (pingsOut *gocbcore.PingKvResult, errOut error) {
signal := make(chan bool, 1)

Expand Down Expand Up @@ -143,7 +122,8 @@ func (b *Bucket) Ping(opts *PingOptions) (*PingResult, error) {
numServices := 0
waitCh := make(chan error, 10)
report := &PingResult{
Services: make(map[ServiceType][]PingServiceEntry),
sdk: Identifier() + " " + "gocbcore/" + gocbcore.Version(),
Services: make(map[ServiceType][]EndpointPingReport),
}
var reportLock sync.Mutex
services := opts.ServiceTypes
Expand Down Expand Up @@ -223,28 +203,27 @@ func (b *Bucket) Ping(opts *PingOptions) (*PingResult, error) {
}

reportLock.Lock()
report.ConfigRev = pings.ConfigRev
report.Services[ServiceTypeKeyValue] = make([]PingServiceEntry, 0)
report.Services[ServiceTypeKeyValue] = make([]EndpointPingReport, 0)
// We intentionally ignore errors here and simply include
// any non-error pings that we have received. Note that
// gocbcore's ping command, when cancelled, still returns
// any pings that had occurred before the operation was
// cancelled and then marks the rest as errors.
for _, ping := range pings.Services {
state := "ok"
state := PingStateOk
detail := ""
if ping.Error != nil {
state = "error"
state = PingStateError
detail = ping.Error.Error()
}

report.Services[ServiceTypeKeyValue] = append(report.Services[ServiceTypeKeyValue], PingServiceEntry{
RemoteAddr: ping.Endpoint,
State: state,
Latency: ping.Latency,
Scope: ping.Scope,
ID: ping.ID,
Detail: detail,
report.Services[ServiceTypeKeyValue] = append(report.Services[ServiceTypeKeyValue], EndpointPingReport{
Remote: ping.Endpoint,
State: state,
Latency: ping.Latency,
Namespace: ping.Scope,
ID: ping.ID,
Error: detail,
})
}
reportLock.Unlock()
Expand All @@ -258,18 +237,18 @@ func (b *Bucket) Ping(opts *PingOptions) (*PingResult, error) {
pingLatency, endpoint, err := httpReq(ServiceTypeQuery, "/admin/ping")

reportLock.Lock()
report.Services[ServiceTypeQuery] = make([]PingServiceEntry, 0)
report.Services[ServiceTypeQuery] = make([]EndpointPingReport, 0)
if err != nil {
report.Services[ServiceTypeQuery] = append(report.Services[ServiceTypeQuery], PingServiceEntry{
RemoteAddr: endpoint,
State: "error",
Detail: err.Error(),
report.Services[ServiceTypeQuery] = append(report.Services[ServiceTypeQuery], EndpointPingReport{
Remote: endpoint,
State: PingStateError,
Error: err.Error(),
})
} else {
report.Services[ServiceTypeQuery] = append(report.Services[ServiceTypeQuery], PingServiceEntry{
RemoteAddr: endpoint,
State: "ok",
Latency: pingLatency,
report.Services[ServiceTypeQuery] = append(report.Services[ServiceTypeQuery], EndpointPingReport{
Remote: endpoint,
State: PingStateOk,
Latency: pingLatency,
})
}
reportLock.Unlock()
Expand All @@ -282,18 +261,18 @@ func (b *Bucket) Ping(opts *PingOptions) (*PingResult, error) {
pingLatency, endpoint, err := httpReq(ServiceTypeSearch, "/api/ping")

reportLock.Lock()
report.Services[ServiceTypeSearch] = make([]PingServiceEntry, 0)
report.Services[ServiceTypeSearch] = make([]EndpointPingReport, 0)
if err != nil {
report.Services[ServiceTypeSearch] = append(report.Services[ServiceTypeSearch], PingServiceEntry{
RemoteAddr: endpoint,
State: "error",
Detail: err.Error(),
report.Services[ServiceTypeSearch] = append(report.Services[ServiceTypeSearch], EndpointPingReport{
Remote: endpoint,
State: PingStateError,
Error: err.Error(),
})
} else {
report.Services[ServiceTypeSearch] = append(report.Services[ServiceTypeSearch], PingServiceEntry{
RemoteAddr: endpoint,
State: "ok",
Latency: pingLatency,
report.Services[ServiceTypeSearch] = append(report.Services[ServiceTypeSearch], EndpointPingReport{
Remote: endpoint,
State: PingStateOk,
Latency: pingLatency,
})
}
reportLock.Unlock()
Expand All @@ -306,18 +285,18 @@ func (b *Bucket) Ping(opts *PingOptions) (*PingResult, error) {
pingLatency, endpoint, err := httpReq(ServiceTypeAnalytics, "/admin/ping")

reportLock.Lock()
report.Services[ServiceTypeAnalytics] = make([]PingServiceEntry, 0)
report.Services[ServiceTypeAnalytics] = make([]EndpointPingReport, 0)
if err != nil {
report.Services[ServiceTypeAnalytics] = append(report.Services[ServiceTypeAnalytics], PingServiceEntry{
RemoteAddr: endpoint,
State: "error",
Detail: err.Error(),
report.Services[ServiceTypeAnalytics] = append(report.Services[ServiceTypeAnalytics], EndpointPingReport{
Remote: endpoint,
State: PingStateError,
Error: err.Error(),
})
} else {
report.Services[ServiceTypeAnalytics] = append(report.Services[ServiceTypeAnalytics], PingServiceEntry{
RemoteAddr: endpoint,
State: "ok",
Latency: pingLatency,
report.Services[ServiceTypeAnalytics] = append(report.Services[ServiceTypeAnalytics], EndpointPingReport{
Remote: endpoint,
State: PingStateOk,
Latency: pingLatency,
})
}
reportLock.Unlock()
Expand Down
40 changes: 18 additions & 22 deletions bucket_ping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,65 +123,61 @@ func TestPingAll(t *testing.T) {
t.Fatalf("Expected services length to be 6 but was %d", len(report.Services))
}

if report.ConfigRev != 64 {
t.Fatalf("Expected report ConfigRev to be 64, was %d", report.ConfigRev)
}

for serviceType, services := range report.Services {
for _, service := range services {
switch serviceType {
case ServiceTypeQuery:
if service.RemoteAddr != "http://localhost:8093" {
t.Fatalf("Expected service RemoteAddr to be http://localhost:8093 but was %s", service.RemoteAddr)
if service.Remote != "http://localhost:8093" {
t.Fatalf("Expected service RemoteAddr to be http://localhost:8093 but was %s", service.Remote)
}

if service.State != "ok" {
t.Fatalf("Expected service state to be ok but was %s", service.State)
if service.State != PingStateOk {
t.Fatalf("Expected service state to be ok but was %d", service.State)
}

if service.Latency < 50*time.Millisecond {
t.Fatalf("Expected service latency to be over 50ms but was %d", service.Latency)
}
case ServiceTypeSearch:
if service.RemoteAddr != "http://localhost:8094" {
t.Fatalf("Expected service RemoteAddr to be http://localhost:8094 but was %s", service.RemoteAddr)
if service.Remote != "http://localhost:8094" {
t.Fatalf("Expected service RemoteAddr to be http://localhost:8094 but was %s", service.Remote)
}

if service.State != "error" {
t.Fatalf("Expected service State to be error but was %s", service.State)
if service.State != PingStateError {
t.Fatalf("Expected service State to be error but was %d", service.State)
}

if service.Latency != 0 {
t.Fatalf("Expected service latency to be 0 but was %d", service.Latency)
}
case ServiceTypeAnalytics:
if service.RemoteAddr != "http://localhost:8095" {
t.Fatalf("Expected service RemoteAddr to be http://localhost:8095 but was %s", service.RemoteAddr)
if service.Remote != "http://localhost:8095" {
t.Fatalf("Expected service RemoteAddr to be http://localhost:8095 but was %s", service.Remote)
}

if service.State != "ok" {
t.Fatalf("Expected service state to be ok but was %s", service.State)
if service.State != PingStateOk {
t.Fatalf("Expected service state to be ok but was %d", service.State)
}

if service.Latency < 20*time.Millisecond {
t.Fatalf("Expected service latency to be over 20ms but was %d", service.Latency)
}
case ServiceTypeKeyValue:
expected, ok := results[service.RemoteAddr]
expected, ok := results[service.Remote]
if !ok {
t.Fatalf("Unexpected service endpoint: %s", service.RemoteAddr)
t.Fatalf("Unexpected service endpoint: %s", service.Remote)
}
if service.Latency != expected.Latency {
t.Fatalf("Expected service Latency to be %s but was %s", expected.Latency, service.Latency)
}

if expected.Error != nil {
if service.State != "error" {
t.Fatalf("Service success should have been error, was %s", service.State)
if service.State != PingStateError {
t.Fatalf("Service success should have been error, was %d", service.State)
}
} else {
if service.State != "ok" {
t.Fatalf("Service success should have been ok, was %s", service.State)
if service.State != PingStateOk {
t.Fatalf("Service success should have been ok, was %d", service.State)
}
}
default:
Expand Down
Loading

0 comments on commit cf84d51

Please sign in to comment.