firehol/netdata

View on GitHub
src/go/plugin/go.d/modules/lighttpd/status.go

Summary

Maintainability
A
0 mins
Test Coverage
// SPDX-License-Identifier: GPL-3.0-or-later

package lighttpd

import (
    "bufio"
    "fmt"
    "io"
    "strconv"
    "strings"
)

const (
    busyWorkers = "BusyWorkers"
    idleWorkers = "IdleWorkers"

    busyServers   = "BusyServers"
    idleServers   = "IdleServers"
    totalAccesses = "Total Accesses"
    totalkBytes   = "Total kBytes"
    uptime        = "Uptime"
    scoreBoard    = "Scoreboard"
)

type (
    serverStatus struct {
        Total struct {
            Accesses *int64 `stm:"accesses"`
            KBytes   *int64 `stm:"kBytes"`
        } `stm:"total"`
        Servers struct {
            Busy *int64 `stm:"busy_servers"`
            Idle *int64 `stm:"idle_servers"`
        } `stm:""`
        Uptime     *int64      `stm:"uptime"`
        Scoreboard *scoreboard `stm:"scoreboard"`
    }
    scoreboard struct {
        Waiting       int64 `stm:"waiting"`
        Open          int64 `stm:"open"`
        Close         int64 `stm:"close"`
        HardError     int64 `stm:"hard_error"`
        KeepAlive     int64 `stm:"keepalive"`
        Read          int64 `stm:"read"`
        ReadPost      int64 `stm:"read_post"`
        Write         int64 `stm:"write"`
        HandleRequest int64 `stm:"handle_request"`
        RequestStart  int64 `stm:"request_start"`
        RequestEnd    int64 `stm:"request_end"`
        ResponseStart int64 `stm:"response_start"`
        ResponseEnd   int64 `stm:"response_end"`
    }
)

func parseResponse(r io.Reader) (*serverStatus, error) {
    s := bufio.NewScanner(r)
    var status serverStatus

    for s.Scan() {
        parts := strings.Split(s.Text(), ":")
        if len(parts) != 2 {
            continue
        }
        key, value := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])

        switch key {
        default:
        case busyWorkers, idleWorkers:
            return nil, fmt.Errorf("found '%s', apache data", key)
        case busyServers:
            status.Servers.Busy = mustParseInt(value)
        case idleServers:
            status.Servers.Idle = mustParseInt(value)
        case totalAccesses:
            status.Total.Accesses = mustParseInt(value)
        case totalkBytes:
            status.Total.KBytes = mustParseInt(value)
        case uptime:
            status.Uptime = mustParseInt(value)
        case scoreBoard:
            status.Scoreboard = parseScoreboard(value)
        }
    }

    return &status, nil
}

func parseScoreboard(value string) *scoreboard {
    // Descriptions from https://blog.serverdensity.com/monitor-lighttpd/
    //
    // “.” = Opening the TCP connection (connect)
    // “C” = Closing the TCP connection if no other HTTP request will use it (close)
    // “E” = hard error
    // “k” = Keeping the TCP connection open for more HTTP requests from the same client to avoid the TCP handling overhead (keep-alive)
    // “r” = ReadAsMap the content of the HTTP request (read)
    // “R” = ReadAsMap the content of the HTTP request (read-POST)
    // “W” = Write the HTTP response to the socket (write)
    // “h” = Decide action to take with the request (handle-request)
    // “q” = Start of HTTP request (request-start)
    // “Q” = End of HTTP request (request-end)
    // “s” = Start of the HTTP request response (response-start)
    // “S” = End of the HTTP request response (response-end)
    // “_” Waiting for Connection (NOTE: not sure, copied the description from apache score board)

    var sb scoreboard
    for _, s := range strings.Split(value, "") {
        switch s {
        case "_":
            sb.Waiting++
        case ".":
            sb.Open++
        case "C":
            sb.Close++
        case "E":
            sb.HardError++
        case "k":
            sb.KeepAlive++
        case "r":
            sb.Read++
        case "R":
            sb.ReadPost++
        case "W":
            sb.Write++
        case "h":
            sb.HandleRequest++
        case "q":
            sb.RequestStart++
        case "Q":
            sb.RequestEnd++
        case "s":
            sb.ResponseStart++
        case "S":
            sb.ResponseEnd++
        }
    }

    return &sb
}

func mustParseInt(value string) *int64 {
    v, err := strconv.ParseInt(value, 10, 64)
    if err != nil {
        panic(err)
    }
    return &v
}