github.com/mackerelio/mackerel-agent-plugins@v0.89.3/mackerel-plugin-php-apc/lib/php-apc.go (about)

     1  package mpphpapc
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"net/http"
     9  	"os"
    10  	"strconv"
    11  	"strings"
    12  
    13  	mp "github.com/mackerelio/go-mackerel-plugin"
    14  	"github.com/urfave/cli"
    15  )
    16  
    17  // metric value structure
    18  var graphdef = map[string]mp.Graphs{
    19  	"php-apc.purges": {
    20  		Label: "PHP APC Cache Purge Count",
    21  		Unit:  "integer",
    22  		Metrics: []mp.Metrics{
    23  			{Name: "cache_full_count", Label: "File Cache", Diff: true, Stacked: false},
    24  			{Name: "user_cache_full_count", Label: "User Cache", Diff: true, Stacked: false},
    25  		},
    26  	},
    27  	"php-apc.stats": {
    28  		Label: "PHP APC File Cache Statistics",
    29  		Unit:  "integer",
    30  		Metrics: []mp.Metrics{
    31  			{Name: "cache_hits", Label: "Hits", Diff: true, Stacked: false},
    32  			{Name: "cache_misses", Label: "Misses", Diff: true, Stacked: false},
    33  		},
    34  	},
    35  	"php-apc.cache_size": {
    36  		Label: "PHP APC Cache Size",
    37  		Unit:  "bytes",
    38  		Metrics: []mp.Metrics{
    39  			{Name: "cached_files_size", Label: "File Cache", Diff: false, Stacked: true},
    40  			{Name: "user_cache_vars_size", Label: "User Cache", Diff: false, Stacked: true},
    41  			{Name: "total_memory", Label: "Total", Diff: false, Stacked: false},
    42  		},
    43  	},
    44  	"php-apc.user_stats": {
    45  		Label: "PHP APC User Cache Statistics",
    46  		Unit:  "integer",
    47  		Metrics: []mp.Metrics{
    48  			{Name: "user_cache_hits", Label: "Hits", Diff: true, Stacked: false},
    49  			{Name: "user_cache_misses", Label: "Misses", Diff: true, Stacked: false},
    50  		},
    51  	},
    52  }
    53  
    54  // PhpApcPlugin mackerel plugin for php-apc
    55  type PhpApcPlugin struct {
    56  	Host     string
    57  	Port     uint16
    58  	Path     string
    59  	Tempfile string
    60  }
    61  
    62  // GraphDefinition interface for mackerelplugin
    63  func (c PhpApcPlugin) GraphDefinition() map[string]mp.Graphs {
    64  	return graphdef
    65  }
    66  
    67  // main function
    68  func doMain(c *cli.Context) error {
    69  
    70  	var phpapc PhpApcPlugin
    71  
    72  	phpapc.Host = c.String("http_host")
    73  	phpapc.Port = uint16(c.Int("http_port"))
    74  	phpapc.Path = c.String("status_page")
    75  
    76  	helper := mp.NewMackerelPlugin(phpapc)
    77  	helper.Tempfile = c.String("tempfile")
    78  
    79  	helper.Run()
    80  	return nil
    81  }
    82  
    83  // FetchMetrics interface for mackerelplugin
    84  func (c PhpApcPlugin) FetchMetrics() (map[string]float64, error) {
    85  	data, err := getPhpApcMetrics(c.Host, c.Port, c.Path)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	stat := make(map[string]float64)
    91  	errStat := parsePhpApcStatus(data, &stat)
    92  	if errStat != nil {
    93  		return nil, errStat
    94  	}
    95  
    96  	return stat, nil
    97  }
    98  
    99  // parsing metrics from server-status?auto
   100  func parsePhpApcStatus(str string, p *map[string]float64) error {
   101  	for _, line := range strings.Split(str, "\n") {
   102  		record := strings.Split(line, ":")
   103  		if len(record) != 2 {
   104  			continue
   105  		}
   106  		var errParse error
   107  		(*p)[record[0]], errParse = strconv.ParseFloat(strings.Trim(record[1], " "), 64)
   108  		if errParse != nil {
   109  			return errParse
   110  		}
   111  	}
   112  
   113  	if len(*p) == 0 {
   114  		return errors.New("status data not found")
   115  	}
   116  
   117  	return nil
   118  }
   119  
   120  // Getting php-apc status from server-status module data.
   121  func getPhpApcMetrics(host string, port uint16, path string) (string, error) {
   122  	uri := "http://" + host + ":" + strconv.FormatUint(uint64(port), 10) + path
   123  	req, err := http.NewRequest(http.MethodGet, uri, nil)
   124  	if err != nil {
   125  		return "", err
   126  	}
   127  	req.Header.Set("User-Agent", "mackerel-plugin-php-apc")
   128  
   129  	resp, err := http.DefaultClient.Do(req)
   130  	if err != nil {
   131  		return "", err
   132  	}
   133  	defer resp.Body.Close()
   134  	if resp.StatusCode != http.StatusOK {
   135  		return "", fmt.Errorf("HTTP status error: %d", resp.StatusCode)
   136  	}
   137  	body, err := io.ReadAll(resp.Body)
   138  	if err != nil {
   139  		return "", err
   140  	}
   141  	return string(body[:]), nil
   142  }
   143  
   144  // Do the plugin
   145  func Do() {
   146  	app := cli.NewApp()
   147  	app.Name = "php-apc_metrics"
   148  	app.Usage = "Get metrics from php-apc."
   149  	app.Author = "Yuichiro Saito"
   150  	app.Email = "saito@heartbeats.jp"
   151  	app.Flags = flags
   152  	app.Action = doMain
   153  
   154  	err := app.Run(os.Args)
   155  	if err != nil {
   156  		log.Fatalln(err)
   157  	}
   158  }