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

     1  package mpphpopcache
     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  var graphdef = map[string]mp.Graphs{
    18  	"php-opcache.memory_size": {
    19  		Label: "PHP OPCache Memory Size",
    20  		Unit:  "integer",
    21  		Metrics: []mp.Metrics{
    22  			{Name: "used_memory", Label: "Used Memory", Diff: false, Stacked: false},
    23  			{Name: "free_memory", Label: "Free Memory", Diff: false, Stacked: false},
    24  			{Name: "wasted_memory", Label: "Wasted Memory", Diff: false, Stacked: false},
    25  		},
    26  	},
    27  	"php-opcache.memory": {
    28  		Label: "PHP OPCache Memory Statistics",
    29  		Unit:  "integer",
    30  		Metrics: []mp.Metrics{
    31  			{Name: "opcache_hit_rate", Label: "OPCache hit rate", Diff: false, Stacked: false},
    32  			{Name: "current_wasted_percentage", Label: "Used Memory", Diff: false, Stacked: false},
    33  		},
    34  	},
    35  
    36  	"php-opcache.cache_size": {
    37  		Label: "PHP OPCache Cache Size",
    38  		Unit:  "integer",
    39  		Metrics: []mp.Metrics{
    40  			{Name: "num_cached_scripts", Label: "Cached Script", Diff: false, Stacked: false},
    41  			{Name: "num_cached_keys", Label: "Num Cached Key", Diff: false, Stacked: false},
    42  			{Name: "max_cached_keys", Label: "Max Cached Key", Diff: false, Stacked: false},
    43  		},
    44  	},
    45  	"php-opcache.stats": {
    46  		Label: "PHP OPCache Cache Statistics",
    47  		Unit:  "integer",
    48  		Metrics: []mp.Metrics{
    49  			{Name: "hits", Label: "Hits", Diff: true, Stacked: false},
    50  			{Name: "misses", Label: "Misses", Diff: true, Stacked: false},
    51  			{Name: "blacklist_misses", Label: "Blacklist Misses", Diff: true, Stacked: false},
    52  		},
    53  	},
    54  }
    55  
    56  // PhpOpcachePlugin mackerel plugin for php-opcache
    57  type PhpOpcachePlugin struct {
    58  	Host     string
    59  	Port     uint16
    60  	Path     string
    61  	Tempfile string
    62  }
    63  
    64  // GraphDefinition interface for mackerelplugin
    65  func (c PhpOpcachePlugin) GraphDefinition() map[string]mp.Graphs {
    66  	return graphdef
    67  }
    68  
    69  // FetchMetrics interface for mackerelplugin
    70  func (c PhpOpcachePlugin) FetchMetrics() (map[string]float64, error) {
    71  	data, err := getPhpOpcacheMetrics(c.Host, c.Port, c.Path)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	stat := make(map[string]float64)
    77  	errStat := parsePhpOpcacheStatus(data, &stat)
    78  	if errStat != nil {
    79  		return nil, errStat
    80  	}
    81  
    82  	return stat, nil
    83  }
    84  
    85  func parsePhpOpcacheStatus(str string, p *map[string]float64) error {
    86  	for _, line := range strings.Split(str, "\n") {
    87  		record := strings.Split(line, ":")
    88  		if len(record) != 2 {
    89  			continue
    90  		}
    91  		var errParse error
    92  		(*p)[record[0]], errParse = strconv.ParseFloat(strings.Trim(record[1], " "), 64)
    93  		if errParse != nil {
    94  			return errParse
    95  		}
    96  	}
    97  
    98  	if len(*p) == 0 {
    99  		return errors.New("status data not found")
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  func getPhpOpcacheMetrics(host string, port uint16, path string) (string, error) {
   106  	uri := "http://" + host + ":" + strconv.FormatUint(uint64(port), 10) + path
   107  	req, err := http.NewRequest(http.MethodGet, uri, nil)
   108  	if err != nil {
   109  		return "", err
   110  	}
   111  	req.Header.Set("User-Agent", "mackerel-plugin-php-opcache")
   112  
   113  	resp, err := http.DefaultClient.Do(req)
   114  	if err != nil {
   115  		return "", err
   116  	}
   117  	defer resp.Body.Close()
   118  	if resp.StatusCode != http.StatusOK {
   119  		return "", fmt.Errorf("HTTP status error: %d", resp.StatusCode)
   120  	}
   121  	body, err := io.ReadAll(resp.Body)
   122  	if err != nil {
   123  		return "", err
   124  	}
   125  	return string(body[:]), nil
   126  }
   127  
   128  func doMain(c *cli.Context) error {
   129  	var phpopcache PhpOpcachePlugin
   130  
   131  	phpopcache.Host = c.String("http_host")
   132  	phpopcache.Port = uint16(c.Int("http_port"))
   133  	phpopcache.Path = c.String("status_page")
   134  
   135  	helper := mp.NewMackerelPlugin(phpopcache)
   136  	helper.Tempfile = c.String("tempfile")
   137  
   138  	helper.Run()
   139  	return nil
   140  }
   141  
   142  // Do the plugin
   143  func Do() {
   144  	app := cli.NewApp()
   145  	app.Name = "php-opcache_metrics"
   146  	app.Usage = "Get metrics from php-opcache."
   147  	app.Author = "Yuichiro Mukai"
   148  	app.Email = "y.iky917@gmail.com"
   149  	app.Flags = flags
   150  	app.Action = doMain
   151  
   152  	err := app.Run(os.Args)
   153  	if err != nil {
   154  		log.Fatalln(err)
   155  	}
   156  }