func main() { configFile := flag.String("c", "", "config file (json)") port := flag.Int("p", 0, "port to listen on") maxprocs := flag.Int("maxprocs", 0, "GOMAXPROCS") debugLevel := flag.Int("d", 0, "enable debug logging") logtostdout := flag.Bool("stdout", false, "write logging output also to stdout") logdir := flag.String("logdir", "/var/log/carbonzipper/", "logging directory") flag.Parse() expvar.NewString("BuildVersion").Set(BuildVersion) if *configFile == "" { log.Fatal("missing config file") } cfgjs, err := ioutil.ReadFile(*configFile) if err != nil { log.Fatal("unable to load config file:", err) } cfgjs = stripCommentHeader(cfgjs) if cfgjs == nil { log.Fatal("error removing header comment from ", *configFile) } err = json.Unmarshal(cfgjs, &Config) if err != nil { log.Fatal("error parsing config file: ", err) } if len(Config.Backends) == 0 { log.Fatal("no Backends loaded -- exiting") } // command line overrides config file if *port != 0 { Config.Port = *port } if *maxprocs != 0 { Config.MaxProcs = *maxprocs } // set up our logging mlog.SetOutput(*logdir, "carbonzipper", *logtostdout) logger = mlog.Level(*debugLevel) logger.Logln("starting carbonzipper", BuildVersion) logger.Logln("setting GOMAXPROCS=", Config.MaxProcs) runtime.GOMAXPROCS(Config.MaxProcs) if Config.ConcurrencyLimitPerServer != 0 { logger.Logln("Setting concurrencyLimit", Config.ConcurrencyLimitPerServer) Limiter = newServerLimiter(Config.Backends, Config.ConcurrencyLimitPerServer) } // +1 to track every over the number of buckets we track timeBuckets = make([]int64, Config.Buckets+1) httputil.PublishTrackedConnections("httptrack") expvar.Publish("requestBuckets", expvar.Func(renderTimeBuckets)) // export config via expvars expvar.Publish("Config", expvar.Func(func() interface{} { return Config })) Metrics.CacheSize = expvar.Func(func() interface{} { return Config.pathCache.ec.Size() }) expvar.Publish("cacheSize", Metrics.CacheSize) Metrics.CacheItems = expvar.Func(func() interface{} { return Config.pathCache.ec.Items() }) expvar.Publish("cacheItems", Metrics.CacheItems) http.HandleFunc("/metrics/find/", httputil.TrackConnections(httputil.TimeHandler(findHandler, bucketRequestTimes))) http.HandleFunc("/render/", httputil.TrackConnections(httputil.TimeHandler(renderHandler, bucketRequestTimes))) http.HandleFunc("/info/", httputil.TrackConnections(httputil.TimeHandler(infoHandler, bucketRequestTimes))) http.HandleFunc("/lb_check", lbCheckHandler) // nothing in the config? check the environment if Config.GraphiteHost == "" { if host := os.Getenv("GRAPHITEHOST") + ":" + os.Getenv("GRAPHITEPORT"); host != ":" { Config.GraphiteHost = host } } // only register g2g if we have a graphite host if Config.GraphiteHost != "" { logger.Logln("Using graphite host", Config.GraphiteHost) // register our metrics with graphite graphite, err := g2g.NewGraphite(Config.GraphiteHost, 60*time.Second, 10*time.Second) if err != nil { log.Fatal("unable to connect to to graphite: ", Config.GraphiteHost, ":", err) } hostname, _ := os.Hostname() hostname = strings.Replace(hostname, ".", "_", -1) graphite.Register(fmt.Sprintf("carbon.zipper.%s.find_requests", hostname), Metrics.FindRequests) graphite.Register(fmt.Sprintf("carbon.zipper.%s.find_errors", hostname), Metrics.FindErrors) graphite.Register(fmt.Sprintf("carbon.zipper.%s.render_requests", hostname), Metrics.RenderRequests) graphite.Register(fmt.Sprintf("carbon.zipper.%s.render_errors", hostname), Metrics.RenderErrors) graphite.Register(fmt.Sprintf("carbon.zipper.%s.info_requests", hostname), Metrics.InfoRequests) graphite.Register(fmt.Sprintf("carbon.zipper.%s.info_errors", hostname), Metrics.InfoErrors) graphite.Register(fmt.Sprintf("carbon.zipper.%s.timeouts", hostname), Metrics.Timeouts) for i := 0; i <= Config.Buckets; i++ { graphite.Register(fmt.Sprintf("carbon.zipper.%s.requests_in_%dms_to_%dms", hostname, i*100, (i+1)*100), bucketEntry(i)) } graphite.Register(fmt.Sprintf("carbon.zipper.%s.cache_size", hostname), Metrics.CacheSize) graphite.Register(fmt.Sprintf("carbon.zipper.%s.cache_items", hostname), Metrics.CacheItems) } // configure the storage client storageClient.Transport = &http.Transport{ MaxIdleConnsPerHost: Config.MaxIdleConnsPerHost, } go probeTlds() // force run now probeForce <- 1 go Config.pathCache.ec.ApproximateCleaner(10 * time.Second) portStr := fmt.Sprintf(":%d", Config.Port) logger.Logln("listening on", portStr) log.Fatal(http.ListenAndServe(portStr, nil)) }
func main() { port := flag.Int("p", 8080, "port to bind to") verbose := flag.Bool("v", false, "enable verbose logging") debug := flag.Bool("vv", false, "enable more verbose (debug) logging") whisperdata := flag.String("w", config.WhisperData, "location where whisper files are stored") maxglobs := flag.Int("maxexpand", config.MaxGlobs, "maximum expansion depth to perform on input via curly braces ({a,b,c})") maxprocs := flag.Int("maxprocs", runtime.NumCPU()*80/100, "GOMAXPROCS") logdir := flag.String("logdir", "/var/log/carbonserver/", "logging directory") logtostdout := flag.Bool("stdout", false, "log also to stdout") scanFrequency := flag.Duration("scanfreq", 0, "file index scan frequency (0 to disable file index)") interval := flag.Duration("i", 60*time.Second, "interval to report internal statistics to graphite") flag.Parse() mlog.SetOutput(*logdir, "carbonserver", *logtostdout) expvar.NewString("BuildVersion").Set(BuildVersion) log.Println("starting carbonserver", BuildVersion) loglevel := mlog.Normal if *verbose { loglevel = mlog.Debug } if *debug { loglevel = mlog.Trace } logger = mlog.Level(loglevel) config.WhisperData = strings.TrimRight(*whisperdata, "/") logger.Logf("reading whisper files from: %s", config.WhisperData) config.MaxGlobs = *maxglobs logger.Logf("maximum brace expansion set to: %d", config.MaxGlobs) if *scanFrequency != 0 { logger.Logln("use file cache with scan frequency", *scanFrequency) force := make(chan struct{}) go fileListUpdater(*whisperdata, time.Tick(*scanFrequency), force) force <- struct{}{} } runtime.GOMAXPROCS(*maxprocs) logger.Logf("set GOMAXPROCS=%d", *maxprocs) httputil.PublishTrackedConnections("httptrack") expvar.Publish("requestBuckets", expvar.Func(renderTimeBuckets)) // +1 to track every over the number of buckets we track timeBuckets = make([]int64, config.Buckets+1) http.HandleFunc("/metrics/find/", httputil.TrackConnections(httputil.TimeHandler(findHandler, bucketRequestTimes))) http.HandleFunc("/render/", httputil.TrackConnections(httputil.TimeHandler(fetchHandler, bucketRequestTimes))) http.HandleFunc("/info/", httputil.TrackConnections(httputil.TimeHandler(infoHandler, bucketRequestTimes))) // nothing in the config? check the environment if config.GraphiteHost == "" { if host := os.Getenv("GRAPHITEHOST") + ":" + os.Getenv("GRAPHITEPORT"); host != ":" { config.GraphiteHost = host } } // only register g2g if we have a graphite host if config.GraphiteHost != "" { logger.Logf("Using graphite host %v", config.GraphiteHost) // register our metrics with graphite graphite, err := g2g.NewGraphite(config.GraphiteHost, *interval, 10*time.Second) if err != nil { log.Fatalf("unable to connect to to graphite: %v: %v", config.GraphiteHost, err) } hostname, _ := os.Hostname() hostname = strings.Replace(hostname, ".", "_", -1) graphite.Register(fmt.Sprintf("carbon.server.%s.render_requests", hostname), Metrics.RenderRequests) graphite.Register(fmt.Sprintf("carbon.server.%s.render_errors", hostname), Metrics.RenderErrors) graphite.Register(fmt.Sprintf("carbon.server.%s.notfound", hostname), Metrics.NotFound) graphite.Register(fmt.Sprintf("carbon.server.%s.find_requests", hostname), Metrics.FindRequests) graphite.Register(fmt.Sprintf("carbon.server.%s.find_errors", hostname), Metrics.FindErrors) graphite.Register(fmt.Sprintf("carbon.server.%s.find_zero", hostname), Metrics.FindZero) for i := 0; i <= config.Buckets; i++ { graphite.Register(fmt.Sprintf("carbon.server.%s.requests_in_%dms_to_%dms", hostname, i*100, (i+1)*100), bucketEntry(i)) } } listen := fmt.Sprintf(":%d", *port) logger.Logf("listening on %s", listen) err := http.ListenAndServe(listen, nil) if err != nil { log.Fatalf("%s", err) } logger.Logf("stopped") }