2018-02-17 12:42:58 +00:00
// Copyright © 2018 Enrico Stahn <enrico.stahn@gmail.com>
// Licensed 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.
package cmd
import (
2018-02-24 11:13:18 +00:00
"context"
2018-02-18 23:53:19 +00:00
"net/http"
2018-02-20 01:33:36 +00:00
"os"
2018-02-24 11:13:18 +00:00
"os/signal"
2020-03-21 11:05:07 +00:00
"syscall"
2018-02-24 11:13:18 +00:00
"time"
2018-02-24 23:08:12 +00:00
"github.com/hipages/php-fpm_exporter/phpfpm"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/cobra"
2018-02-17 12:42:58 +00:00
)
// Configuration variables
var (
2018-02-24 11:13:18 +00:00
listeningAddress string
metricsEndpoint string
scrapeURIs [ ] string
2018-02-24 13:36:13 +00:00
fixProcessCount bool
2018-02-17 12:42:58 +00:00
)
// serverCmd represents the server command
var serverCmd = & cobra . Command {
Use : "server" ,
Short : "A brief description of your command" ,
Long : ` A longer description that spans multiple lines and likely contains examples
and usage of using your command . For example :
Cobra is a CLI library for Go that empowers applications .
This application is a tool to generate the needed files
to quickly create a Cobra application . ` ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
log . Infof ( "Starting server on %v with path %v" , listeningAddress , metricsEndpoint )
pm := phpfpm . PoolManager { }
for _ , uri := range scrapeURIs {
pm . Add ( uri )
}
exporter := phpfpm . NewExporter ( pm )
2018-02-24 13:36:13 +00:00
if fixProcessCount {
log . Info ( "Idle/Active/Total Processes will be calculated by php-fpm_exporter." )
2018-02-28 11:22:35 +00:00
exporter . CountProcessState = true
2018-02-24 13:36:13 +00:00
}
2018-02-17 12:42:58 +00:00
prometheus . MustRegister ( exporter )
2018-02-24 11:13:18 +00:00
srv := & http . Server {
Addr : listeningAddress ,
// Good practice to set timeouts to avoid Slowloris attacks.
WriteTimeout : time . Second * 15 ,
ReadTimeout : time . Second * 15 ,
IdleTimeout : time . Second * 60 ,
}
2018-02-17 12:42:58 +00:00
http . Handle ( metricsEndpoint , promhttp . Handler ( ) )
http . HandleFunc ( "/" , func ( w http . ResponseWriter , r * http . Request ) {
2020-03-04 05:34:23 +00:00
_ , err := w . Write ( [ ] byte ( ` < html >
2018-02-24 11:13:18 +00:00
< head > < title > php - fpm_exporter < / title > < / head >
2018-02-17 12:42:58 +00:00
< body >
2018-02-24 11:13:18 +00:00
< h1 > php - fpm_exporter < / h1 >
2018-02-17 12:42:58 +00:00
< p > < a href = ' ` + metricsEndpoint + ` ' > Metrics < / a > < / p >
< / body >
< / html > ` ) )
2020-03-04 05:34:23 +00:00
if err != nil {
log . Error ( )
}
2018-02-17 12:42:58 +00:00
} )
2018-02-24 11:13:18 +00:00
// Run our server in a goroutine so that it doesn't block.
go func ( ) {
if err := srv . ListenAndServe ( ) ; err != nil {
log . Error ( err )
}
} ( )
c := make ( chan os . Signal , 1 )
2020-03-21 11:05:07 +00:00
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) or SIGTERM
// SIGKILL, SIGQUIT will not be caught.
signal . Notify ( c , os . Interrupt , syscall . SIGTERM )
2018-02-24 11:13:18 +00:00
// Block until we receive our signal.
<- c
// Create a deadline to wait for.
var wait time . Duration
ctx , cancel := context . WithTimeout ( context . Background ( ) , wait )
defer cancel ( )
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
2018-02-25 10:45:46 +00:00
if err := srv . Shutdown ( ctx ) ; err != nil {
log . Fatal ( "Error during shutdown" , err )
}
2018-02-24 11:13:18 +00:00
// Optionally, you could run srv.Shutdown in a goroutine and block on
// <-ctx.Done() if your application should wait for other services
// to finalize based on context cancellation.
log . Info ( "Shutting down" )
os . Exit ( 0 )
2018-02-17 12:42:58 +00:00
} ,
}
func init ( ) {
RootCmd . AddCommand ( serverCmd )
2018-02-18 23:53:19 +00:00
serverCmd . Flags ( ) . StringVar ( & listeningAddress , "web.listen-address" , ":9253" , "Address on which to expose metrics and web interface." )
serverCmd . Flags ( ) . StringVar ( & metricsEndpoint , "web.telemetry-path" , "/metrics" , "Path under which to expose metrics." )
serverCmd . Flags ( ) . StringSliceVar ( & scrapeURIs , "phpfpm.scrape-uri" , [ ] string { "tcp://127.0.0.1:9000/status" } , "FastCGI address, e.g. unix:///tmp/php.sock;/status or tcp://127.0.0.1:9000/status" )
2018-02-24 13:36:13 +00:00
serverCmd . Flags ( ) . BoolVar ( & fixProcessCount , "phpfpm.fix-process-count" , false , "Enable to calculate process numbers via php-fpm_exporter since PHP-FPM sporadically reports wrong active/idle/total process numbers." )
2018-02-20 01:33:36 +00:00
//viper.BindEnv("web.listen-address", "PHP_FPM_WEB_LISTEN_ADDRESS")
//viper.BindPFlag("web.listen-address", serverCmd.Flags().Lookup("web.listen-address"))
// Workaround since vipers BindEnv is currently not working as expected (see https://github.com/spf13/viper/issues/461)
envs := map [ string ] string {
"PHP_FPM_WEB_LISTEN_ADDRESS" : "web.listen-address" ,
"PHP_FPM_WEB_TELEMETRY_PATH" : "web.telemetry-path" ,
"PHP_FPM_SCRAPE_URI" : "phpfpm.scrape-uri" ,
2018-02-24 13:36:13 +00:00
"PHP_FPM_FIX_PROCESS_COUNT" : "phpfpm.fix-process-count" ,
2018-02-20 01:33:36 +00:00
}
2018-02-25 11:14:25 +00:00
mapEnvVars ( envs , serverCmd )
2018-02-17 12:42:58 +00:00
}