func processUptime(passengerDetails *passengerStatus) Stats {
	var upTimes []int
	processes := passengerDetails.Processes
	for _, processStats := range processes {
		SpawnedNano := time.Unix(0, int64(processStats.SpawnTime*1000))
		uptime := time.Since(SpawnedNano)
		upTimes = append(upTimes, int(uptime.Minutes()))
	}
	return summarizeStats(&upTimes)
}
Timestamps from Passenger Status are returned in microseconds (1/1,000,000 second) units
Golang unix time function only accepts seconds or nano (1/1,000,000,000) seconds
multiplying by 1000 to get nano from micro
package main
import (
	"bytes"
	"encoding/xml"
	"flag"
	"fmt"
	"io"
	"log"
	"os/exec"
	"sort"
	"strconv"
	"strings"
	"time"
	"github.com/theckman/godspeed"
	"golang.org/x/net/html/charset"
)
const (
	DefaultHost = godspeed.DefaultHost
	DefaultPort = godspeed.DefaultPort
	DefaultAutoTruncate = false
)
var printOutput bool
type passengerStatus struct {
	XMLName      xml.Name  `xml:"info"`
	ProcessCount int       `xml:"process_count"`
	PoolMax      int       `xml:"max"`
	PoolCurrent  int       `xml:"capacity_used"`
	QueuedCount  []int     `xml:"supergroups>supergroup>group>get_wait_list_size"`
	Processes    []process `xml:"supergroups>supergroup>group>processes>process"`
}
type process struct {
	CurrentSessions int   `xml:"sessions"`
	Processed       int   `xml:"processed"`
	SpawnTime       int64 `xml:"spawn_end_time"`
	CPU             int   `xml:"cpu"`
	Memory          int   `xml:"real_memory"`
	PID             int   `xml:"pid"`
	LastUsed        int64 `xml:"last_used"`
}
type Stats struct {
	min int
	len int
	avg int
	max int
	sum int
}
func summarizeStats(statsArray *[]int) Stats {
	var processedStats Stats
	sum, count := 0, len(*statsArray)
	sort.Sort(sort.IntSlice(*statsArray))
	for _, stat := range *statsArray {
		sum += stat
	}
	sortedStats := *statsArray
	processedStats.min = sortedStats[0]
	processedStats.len = count
	processedStats.avg = sum / count
	processedStats.max = sortedStats[len(sortedStats)-1]
	processedStats.sum = sum
	return processedStats
}
func retrievePassengerStats() (io.Reader, error) {
	out, err := exec.Command("passenger-status", "--show=xml").Output()
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	return bytes.NewReader(out), nil
}
func parsePassengerXML(xmlData *io.Reader) (passengerStatus, error) {
	var ParsedPassengerXML passengerStatus
	dec := xml.NewDecoder(*xmlData)
	dec.CharsetReader = charset.NewReaderLabel
	err := dec.Decode(&ParsedPassengerXML)
	if err != nil {
		return passengerStatus{}, err
	}
	return ParsedPassengerXML, nil
}
func floatMyInt(value int) float64 {
	return float64(value)
}
func getProcessThreadCount(pid int) (int, error) {
	out, err := exec.Command("ps", "--no-header", "-o", "nlwp", strconv.Itoa(pid)).Output()
	if err != nil {
		return 0, fmt.Errorf("encountered error issuing command to retrieve"+
			" thread count from pid %d, error: %s", pid, err)
	}
	countString := strings.TrimSpace(string(out))
	count, err := strconv.Atoi(countString)
	if err != nil {
		return 0, fmt.Errorf("encountered error parsing thread count from command return value, err: %s", err)
	}
	return count, nil
}
func processed(passengerDetails *passengerStatus) Stats {
	var processed []int
	processes := passengerDetails.Processes
	for _, processStats := range processes {
		processed = append(processed, processStats.Processed)
	}
	return summarizeStats(&processed)
}
func memory(passengerDetails *passengerStatus) Stats {
	var memory []int
	processes := passengerDetails.Processes
	for _, processStats := range processes {
		memory = append(memory, processStats.Memory)
	}
	return summarizeStats(&memory)
}