TUN-8792: Make diag/system endpoint always return a JSON

## Summary
Change the system information collector and respective http handler so that it always returns a JSON.

Closes [TUN-8792](https://jira.cfdata.org/browse/TUN-8792)
This commit is contained in:
Luis Neto
2024-12-11 02:48:41 -08:00
parent ba9f28ef43
commit 02e7ffd5b7
8 changed files with 288 additions and 141 deletions

View File

@@ -1,6 +1,82 @@
package diagnostic
import "context"
import (
"context"
"encoding/json"
"errors"
"strings"
)
type SystemInformationError struct {
Err error `json:"error"`
RawInfo string `json:"rawInfo"`
}
func (err SystemInformationError) Error() string {
return err.Err.Error()
}
func (err SystemInformationError) MarshalJSON() ([]byte, error) {
s := map[string]string{
"error": err.Err.Error(),
"rawInfo": err.RawInfo,
}
return json.Marshal(s)
}
type SystemInformationGeneralError struct {
OperatingSystemInformationError error
MemoryInformationError error
FileDescriptorsInformationError error
DiskVolumeInformationError error
}
func (err SystemInformationGeneralError) Error() string {
builder := &strings.Builder{}
builder.WriteString("errors found:")
if err.OperatingSystemInformationError != nil {
builder.WriteString(err.OperatingSystemInformationError.Error() + ", ")
}
if err.MemoryInformationError != nil {
builder.WriteString(err.MemoryInformationError.Error() + ", ")
}
if err.FileDescriptorsInformationError != nil {
builder.WriteString(err.FileDescriptorsInformationError.Error() + ", ")
}
if err.DiskVolumeInformationError != nil {
builder.WriteString(err.DiskVolumeInformationError.Error() + ", ")
}
return builder.String()
}
func (err SystemInformationGeneralError) MarshalJSON() ([]byte, error) {
data := map[string]SystemInformationError{}
var sysErr SystemInformationError
if errors.As(err.OperatingSystemInformationError, &sysErr) {
data["operatingSystemInformationError"] = sysErr
}
if errors.As(err.MemoryInformationError, &sysErr) {
data["memoryInformationError"] = sysErr
}
if errors.As(err.FileDescriptorsInformationError, &sysErr) {
data["fileDescriptorsInformationError"] = sysErr
}
if errors.As(err.DiskVolumeInformationError, &sysErr) {
data["diskVolumeInformationError"] = sysErr
}
return json.Marshal(data)
}
type DiskVolumeInformation struct {
Name string `json:"name"` // represents the filesystem in linux/macos or device name in windows
@@ -17,17 +93,19 @@ func NewDiskVolumeInformation(name string, maximum, current uint64) *DiskVolumeI
}
type SystemInformation struct {
MemoryMaximum uint64 `json:"memoryMaximum"` // represents the maximum memory of the system in kilobytes
MemoryCurrent uint64 `json:"memoryCurrent"` // represents the system's memory in use in kilobytes
FileDescriptorMaximum uint64 `json:"fileDescriptorMaximum"` // represents the maximum number of file descriptors of the system
FileDescriptorCurrent uint64 `json:"fileDescriptorCurrent"` // represents the system's file descriptors in use
OsSystem string `json:"osSystem"` // represents the operating system name i.e.: linux, windows, darwin
HostName string `json:"hostName"` // represents the system host name
OsVersion string `json:"osVersion"` // detailed information about the system's release version level
OsRelease string `json:"osRelease"` // detailed information about the system's release
Architecture string `json:"architecture"` // represents the system's hardware platform i.e: arm64/amd64
CloudflaredVersion string `json:"cloudflaredVersion"` // the runtime version of cloudflared
Disk []*DiskVolumeInformation `json:"disk"`
MemoryMaximum uint64 `json:"memoryMaximum,omitempty"` // represents the maximum memory of the system in kilobytes
MemoryCurrent uint64 `json:"memoryCurrent,omitempty"` // represents the system's memory in use in kilobytes
FileDescriptorMaximum uint64 `json:"fileDescriptorMaximum,omitempty"` // represents the maximum number of file descriptors of the system
FileDescriptorCurrent uint64 `json:"fileDescriptorCurrent,omitempty"` // represents the system's file descriptors in use
OsSystem string `json:"osSystem,omitempty"` // represents the operating system name i.e.: linux, windows, darwin
HostName string `json:"hostName,omitempty"` // represents the system host name
OsVersion string `json:"osVersion,omitempty"` // detailed information about the system's release version level
OsRelease string `json:"osRelease,omitempty"` // detailed information about the system's release
Architecture string `json:"architecture,omitempty"` // represents the system's hardware platform i.e: arm64/amd64
CloudflaredVersion string `json:"cloudflaredVersion,omitempty"` // the runtime version of cloudflared
GoVersion string `json:"goVersion,omitempty"`
GoArch string `json:"goArch,omitempty"`
Disk []*DiskVolumeInformation `json:"disk,omitempty"`
}
func NewSystemInformation(
@@ -40,7 +118,9 @@ func NewSystemInformation(
osVersion,
osRelease,
architecture,
cloudflaredVersion string,
cloudflaredVersion,
goVersion,
goArchitecture string,
disk []*DiskVolumeInformation,
) *SystemInformation {
return &SystemInformation{
@@ -54,17 +134,17 @@ func NewSystemInformation(
osRelease,
architecture,
cloudflaredVersion,
goVersion,
goArchitecture,
disk,
}
}
type SystemCollector interface {
// If the collection is successful it will return `SystemInformation` struct,
// an empty string, and a nil error.
// In case there is an error a string with the raw data will be returned
// however the returned string not contain all the data points.
// and a nil error.
//
// This function expects that the caller sets the context timeout to prevent
// long-lived collectors.
Collect(ctx context.Context) (*SystemInformation, string, error)
Collect(ctx context.Context) (*SystemInformation, error)
}