blob: 639e2cf68936da94f8bf7cd60f6351c3c244faef [file]
package cache
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import (
"fmt"
"strconv"
"strings"
)
// DSStat is a single Delivery Service statistic, which is associated with
// a particular cache server.
// DSStats are referenced by name in a map associated with cache server data,
// and so that name (XMLID) is not reiterated here.
type DSStat struct {
// InBytes is the total number of bytes received by the cache server which
// were for the Delivery Service.
InBytes uint64
// OutBytes is the total number of bytes transmitted by the cache server
// in service of the Delivery Service.
OutBytes uint64
// Status2xx is the number of requests for the Delivery Service's content
// that were served with responses having response codes on the interval
// [200, 300).
Status2xx uint64
// Status3xx is the number of requests for the Delivery Service's content
// that were served with responses having response codes on the interval
// [300, 400).
Status3xx uint64
// Status4xx is the number of requests for the Delivery Service's content
// that were served with responses having response codes on the interval
// [400, 500).
Status4xx uint64
// Status2xx is the number of requests for the Delivery Service's content
// that were served with responses having response codes on the interval
// [500, 600).
Status5xx uint64
}
// Loadavg contains the parsed "loadavg" data for a polled cache server.
// Specifically, it contains all of the data stored that can be found in
// /proc/loadavg on a Linux/Unix system.
//
// For more information on what a "loadavg" is, consult the “proc(5)” man page
// (web-hosted: https://linux.die.net/man/5/proc).
type Loadavg struct {
// One is the cache server's "loadavg" in the past minute from the time it was
// polled.
One float64
// Five is the cache server's "loadavg" in the past five minutes from the time
// it was polled.
Five float64
// Fifteen is the cache server's "loadavg" in the past fifteen minutes from the
// time it was polled.
Fifteen float64
// CurrentProcesses is the number of currently executing processes (or threads)
// on the cache server.
// Note that stats_over_http doesn't provide this, so in general it can't be
// relied on to be set properly.
CurrentProcesses uint64
// TotalProcesses is the number of total processes (or threads) that exist on
// the cache server.
TotalProcesses uint64
// LatestPID is the process ID of the most recently created process on the
// cache server at the time of polling.
// Note that stats_over_http doesn't provide this, so in general it can't be
// relied on to be set properly - which is fine because what use could that
// information actually have??
LatestPID int64
}
func splitLoadavgOn(char rune) bool {
return char == ' ' || char == '/' || char == '\t'
}
// LoadavgFromRawLine parses a raw line - presumably read from /proc/loadavg -
// and returns a Loadavg containing all of the same information, as well as
// any encountered error.
func LoadavgFromRawLine(line string) (Loadavg, error) {
var load Loadavg
fields := strings.FieldsFunc(line, splitLoadavgOn)
if len(fields) != 6 {
return load, fmt.Errorf("Expected 6 fields in a loadavg line, got %d", len(fields))
}
if loadStat, err := strconv.ParseFloat(fields[0], 64); err != nil {
return load, fmt.Errorf("Error parsing one-minute loadavg: %v", err)
} else {
load.One = loadStat
}
if loadStat, err := strconv.ParseFloat(fields[1], 64); err != nil {
return load, fmt.Errorf("Error parsing five-minute loadavg: %v", err)
} else {
load.Five = loadStat
}
if loadStat, err := strconv.ParseFloat(fields[2], 64); err != nil {
return load, fmt.Errorf("Error parsing fifteen-minute loadavg: %v", err)
} else {
load.Fifteen = loadStat
}
if loadStat, err := strconv.ParseUint(fields[3], 10, 64); err != nil {
return load, fmt.Errorf("Error parsing currently executing processes: %v", err)
} else {
load.CurrentProcesses = loadStat
}
if loadStat, err := strconv.ParseUint(fields[4], 10, 64); err != nil {
return load, fmt.Errorf("Error parsing total processes: %v", err)
} else {
load.TotalProcesses = loadStat
}
if loadStat, err := strconv.ParseInt(fields[5], 10, 64); err != nil {
return load, fmt.Errorf("Error parsing latest process ID: %v", err)
} else {
load.LatestPID = loadStat
}
return load, nil
}
// Interface represents a network interface. The name of the interface is
// used to access it within a Statistics object, and so is not stored here.
type Interface struct {
// Speed is the "speed" of the interface, which is of unknown - but vitally
// important - meaning.
Speed int64
// BytesOut is the total number of bytes transmitted by this interface.
BytesOut uint64
// BytesIn is the total number of bytes received by this interface.
BytesIn uint64
}
// Statistics is a structure containing, most generally, the statistics of a
// cache server.
type Statistics struct {
// Loadavg contains the Unix/Linux "loadavg" values for the cache server.
Loadavg Loadavg
// Interfaces is a map of network interface names to statistic data about
// those interfaces.
Interfaces map[string]Interface
// NotAvailable reports whether or not the cache server is unavailable.
// Sometimes caches can directly report this, but it's not supported by
// stats_over_http (afaik), so it always just uses ``false''
NotAvailable bool
}
// AddInterfaceFromRawLine parses the raw line - presumably read from
// /proc/net/dev - and inserts into the Statistics a new Interface
// containing the data provided.
//
// This will initialize s.Interfaces if that has not already been done (if the
// parse is successful).
//
// If the line cannot be parsed, s.Interfaces is unchanged and an error
// describing the problem is returned.
//
// Note that this does *not* set the interface's Speed.
func (s *Statistics) AddInterfaceFromRawLine(line string) error {
var iface Interface
parts := strings.Split(line, ":")
if len(parts) != 2 {
return fmt.Errorf("Expected /proc/net/dev line to be in the format '{{name}}:{{info}}', but got '%s'", line)
}
name := parts[0]
parts = strings.Fields(parts[1])
if len(parts) < 9 {
return fmt.Errorf("Expected at least 9 /proc/net/dev fields, got %d", len(parts))
}
var err error
if iface.BytesIn, err = strconv.ParseUint(parts[0], 10, 64); err != nil {
return fmt.Errorf("Error parsing BytesIn: %v", err)
}
if iface.BytesOut, err = strconv.ParseUint(parts[8], 10, 64); err != nil {
return fmt.Errorf("Error parsing BytesOut: %v", err)
}
if s.Interfaces == nil {
s.Interfaces = map[string]Interface{
name: iface,
}
} else {
s.Interfaces[name] = iface
}
return nil
}