func NewReaper(cnf *conf.Config) *Reaper {
	rpr := &Reaper{
		lg:           common.NewLogger("reaper", cnf),
		spanExpiryMs: cnf.GetInt64(conf.HTRACE_SPAN_EXPIRY_MS),
		heartbeats:   make(chan interface{}, 1),
	}
	if rpr.spanExpiryMs >= MAX_SPAN_EXPIRY_MS {
		rpr.spanExpiryMs = MAX_SPAN_EXPIRY_MS
	} else if rpr.spanExpiryMs <= 0 {
		rpr.spanExpiryMs = MAX_SPAN_EXPIRY_MS
	}
	rpr.hb = NewHeartbeater("ReaperHeartbeater",
		cnf.GetInt64(conf.HTRACE_REAPER_HEARTBEAT_PERIOD_MS), rpr.lg)
	rpr.exited.Add(1)
	go rpr.run()
	rpr.hb.AddHeartbeatTarget(&HeartbeatTarget{
		name:       "reaper",
		targetChan: rpr.heartbeats,
	})
	var when string
	if rpr.spanExpiryMs >= MAX_SPAN_EXPIRY_MS {
		when = "never"
	} else {
		when = "after " + time.Duration(rpr.spanExpiryMs).String()
	}
	rpr.lg.Infof("Initializing span reaper: span time out = %s.\n", when)
	return rpr
}
Example #2
0
func CreateRestServer(cnf *conf.Config, store *dataStore) (*RestServer, error) {
	var err error
	rsv := &RestServer{}
	rsv.listener, err = net.Listen("tcp", cnf.Get(conf.HTRACE_WEB_ADDRESS))
	if err != nil {
		return nil, err
	}
	var success bool
	defer func() {
		if !success {
			rsv.Close()
		}
	}()
	rsv.lg = common.NewLogger("rest", cnf)

	r := mux.NewRouter().StrictSlash(false)

	r.Handle("/server/info", &serverInfoHandler{lg: rsv.lg}).Methods("GET")

	serverStatsH := &serverStatsHandler{dataStoreHandler: dataStoreHandler{
		store: store, lg: rsv.lg}}
	r.Handle("/server/stats", serverStatsH).Methods("GET")

	writeSpansH := &writeSpansHandler{dataStoreHandler: dataStoreHandler{
		store: store, lg: rsv.lg}}
	r.Handle("/writeSpans", writeSpansH).Methods("POST")

	queryH := &queryHandler{lg: rsv.lg, dataStoreHandler: dataStoreHandler{store: store}}
	r.Handle("/query", queryH).Methods("GET")

	span := r.PathPrefix("/span").Subrouter()
	findSidH := &findSidHandler{dataStoreHandler: dataStoreHandler{store: store, lg: rsv.lg}}
	span.Handle("/{id}", findSidH).Methods("GET")

	findChildrenH := &findChildrenHandler{dataStoreHandler: dataStoreHandler{store: store,
		lg: rsv.lg}}
	span.Handle("/{id}/children", findChildrenH).Methods("GET")

	// Default Handler. This will serve requests for static requests.
	webdir := os.Getenv("HTRACED_WEB_DIR")
	if webdir == "" {
		webdir, err = filepath.Abs(filepath.Join(filepath.Dir(os.Args[0]), "..", "web"))

		if err != nil {
			return nil, err
		}
	}

	rsv.lg.Infof("Serving static files from %s\n.", webdir)
	r.PathPrefix("/").Handler(http.FileServer(http.Dir(webdir))).Methods("GET")

	// Log an error message for unknown non-GET requests.
	r.PathPrefix("/").Handler(&logErrorHandler{lg: rsv.lg})

	go http.Serve(rsv.listener, r)

	rsv.lg.Infof("Started REST server on %s...\n", rsv.listener.Addr().String())
	success = true
	return rsv, nil
}
Example #3
0
func NewMetricsSink(cnf *conf.Config) *MetricsSink {
	return &MetricsSink{
		lg:               common.NewLogger("metrics", cnf),
		maxMtx:           cnf.GetInt(conf.HTRACE_METRICS_MAX_ADDR_ENTRIES),
		HostSpanMetrics:  make(common.SpanMetricsMap),
		wsLatencyCircBuf: NewCircBufU32(LATENCY_CIRC_BUF_SIZE),
	}
}
Example #4
0
func CreateRestServer(cnf *conf.Config, store *dataStore,
	listener net.Listener) (*RestServer, error) {
	var err error
	rsv := &RestServer{}
	rsv.lg = common.NewLogger("rest", cnf)

	r := mux.NewRouter().StrictSlash(false)

	r.Handle("/server/info", &serverVersionHandler{lg: rsv.lg}).Methods("GET")
	r.Handle("/server/version", &serverVersionHandler{lg: rsv.lg}).Methods("GET")
	r.Handle("/server/debugInfo", &serverDebugInfoHandler{lg: rsv.lg}).Methods("GET")

	serverStatsH := &serverStatsHandler{dataStoreHandler: dataStoreHandler{
		store: store, lg: rsv.lg}}
	r.Handle("/server/stats", serverStatsH).Methods("GET")

	serverConfH := &serverConfHandler{cnf: cnf, lg: rsv.lg}
	r.Handle("/server/conf", serverConfH).Methods("GET")

	writeSpansH := &writeSpansHandler{dataStoreHandler: dataStoreHandler{
		store: store, lg: rsv.lg}}
	r.Handle("/writeSpans", writeSpansH).Methods("POST")

	queryH := &queryHandler{lg: rsv.lg, dataStoreHandler: dataStoreHandler{store: store}}
	r.Handle("/query", queryH).Methods("GET")

	span := r.PathPrefix("/span").Subrouter()
	findSidH := &findSidHandler{dataStoreHandler: dataStoreHandler{store: store, lg: rsv.lg}}
	span.Handle("/{id}", findSidH).Methods("GET")

	findChildrenH := &findChildrenHandler{dataStoreHandler: dataStoreHandler{store: store,
		lg: rsv.lg}}
	span.Handle("/{id}/children", findChildrenH).Methods("GET")

	// Default Handler. This will serve requests for static requests.
	webdir := os.Getenv("HTRACED_WEB_DIR")
	if webdir == "" {
		webdir, err = filepath.Abs(filepath.Join(filepath.Dir(os.Args[0]), "..", "web"))
		if err != nil {
			return nil, err
		}
	}

	rsv.lg.Infof(`Serving static files from "%s"`+"\n", webdir)
	r.PathPrefix("/").Handler(http.FileServer(http.Dir(webdir))).Methods("GET")

	// Log an error message for unknown non-GET requests.
	r.PathPrefix("/").Handler(&logErrorHandler{lg: rsv.lg})

	rsv.listener = listener
	rsv.Handler = r
	rsv.ErrorLog = rsv.lg.Wrap("[REST] ", common.INFO)
	go rsv.Serve(rsv.listener)
	rsv.lg.Infof("Started REST server on %s\n", rsv.listener.Addr().String())
	return rsv, nil
}
Example #5
0
func main() {
	for idx := range os.Args {
		arg := os.Args[idx]
		if strings.HasPrefix(arg, "--h") || strings.HasPrefix(arg, "-h") {
			fmt.Fprintf(os.Stderr, USAGE)
			os.Exit(0)
		}
	}
	cnf := common.LoadApplicationConfig()
	common.InstallSignalHandlers(cnf)
	lg := common.NewLogger("main", cnf)
	defer lg.Close()
	store, err := CreateDataStore(cnf, nil)
	if err != nil {
		lg.Errorf("Error creating datastore: %s\n", err.Error())
		os.Exit(1)
	}
	var rsv *RestServer
	rsv, err = CreateRestServer(cnf, store)
	if err != nil {
		lg.Errorf("Error creating REST server: %s\n", err.Error())
		os.Exit(1)
	}
	var hsv *HrpcServer
	if cnf.Get(conf.HTRACE_HRPC_ADDRESS) != "" {
		hsv, err = CreateHrpcServer(cnf, store)
		if err != nil {
			lg.Errorf("Error creating HRPC server: %s\n", err.Error())
			os.Exit(1)
		}
	} else {
		lg.Infof("Not starting HRPC server because no value was given for %s.\n",
			conf.HTRACE_HRPC_ADDRESS)
	}
	naddr := cnf.Get(conf.HTRACE_STARTUP_NOTIFICATION_ADDRESS)
	if naddr != "" {
		notif := StartupNotification{
			HttpAddr:  rsv.Addr().String(),
			ProcessId: os.Getpid(),
		}
		if hsv != nil {
			notif.HrpcAddr = hsv.Addr().String()
		}
		err = sendStartupNotification(naddr, &notif)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to send startup notification: "+
				"%s\n", err.Error())
			os.Exit(1)
		}
	}
	for {
		time.Sleep(time.Duration(10) * time.Hour)
	}
}
func TestHeartbeaterStartupShutdown(t *testing.T) {
	cnfBld := conf.Builder{
		Values:   conf.TEST_VALUES(),
		Defaults: conf.DEFAULTS,
	}
	cnf, err := cnfBld.Build()
	if err != nil {
		t.Fatalf("failed to create conf: %s", err.Error())
	}
	lg := common.NewLogger("heartbeater", cnf)
	hb := NewHeartbeater("ExampleHeartbeater", 1, lg)
	if hb.String() != "ExampleHeartbeater" {
		t.Fatalf("hb.String() returned %s instead of %s\n", hb.String(), "ExampleHeartbeater")
	}
	hb.Shutdown()
}
Example #7
0
func CreateHrpcServer(cnf *conf.Config, store *dataStore,
	testHooks *hrpcTestHooks) (*HrpcServer, error) {
	lg := common.NewLogger("hrpc", cnf)
	numHandlers := cnf.GetInt(conf.HTRACE_NUM_HRPC_HANDLERS)
	if numHandlers < 1 {
		lg.Warnf("%s must be positive: using 1 handler.\n", conf.HTRACE_NUM_HRPC_HANDLERS)
		numHandlers = 1
	}
	if numHandlers > MAX_HRPC_HANDLERS {
		lg.Warnf("%s cannot be more than %d: using %d handlers\n",
			conf.HTRACE_NUM_HRPC_HANDLERS, MAX_HRPC_HANDLERS, MAX_HRPC_HANDLERS)
		numHandlers = MAX_HRPC_HANDLERS
	}
	hsv := &HrpcServer{
		Server: rpc.NewServer(),
		hand: &HrpcHandler{
			lg:    lg,
			store: store,
		},
		cdcs:     make(chan *HrpcServerCodec, numHandlers),
		shutdown: make(chan interface{}),
		ioTimeo: time.Millisecond *
			time.Duration(cnf.GetInt64(conf.HTRACE_HRPC_IO_TIMEOUT_MS)),
		testHooks: testHooks,
	}
	for i := 0; i < numHandlers; i++ {
		hsv.cdcs <- &HrpcServerCodec{
			lg:  lg,
			hsv: hsv,
			msgpackHandle: codec.MsgpackHandle{
				WriteExt: true,
			},
		}
	}
	var err error
	hsv.listener, err = net.Listen("tcp", cnf.Get(conf.HTRACE_HRPC_ADDRESS))
	if err != nil {
		return nil, err
	}
	hsv.Server.Register(hsv.hand)
	hsv.exited.Add(1)
	go hsv.run()
	lg.Infof("Started HRPC server on %s with %d handler routines. "+
		"ioTimeo=%s.\n", hsv.listener.Addr().String(), numHandlers,
		hsv.ioTimeo.String())
	return hsv, nil
}
Example #8
0
func CreateHrpcServer(cnf *conf.Config, store *dataStore) (*HrpcServer, error) {
	lg := common.NewLogger("hrpc", cnf)
	hsv := &HrpcServer{
		Server: rpc.NewServer(),
		hand: &HrpcHandler{
			lg:    lg,
			store: store,
		},
	}
	var err error
	hsv.listener, err = net.Listen("tcp", cnf.Get(conf.HTRACE_HRPC_ADDRESS))
	if err != nil {
		return nil, err
	}
	hsv.Server.Register(hsv.hand)
	go hsv.run()
	lg.Infof("Started HRPC server on %s...\n", hsv.listener.Addr().String())
	return hsv, nil
}
Example #9
0
func CreateDataStore(cnf *conf.Config, writtenSpans chan *common.Span) (*dataStore, error) {
	// Get the configuration.
	clearStored := cnf.GetBool(conf.HTRACE_DATA_STORE_CLEAR)
	dirsStr := cnf.Get(conf.HTRACE_DATA_STORE_DIRECTORIES)
	dirs := strings.Split(dirsStr, conf.PATH_LIST_SEP)

	var err error
	lg := common.NewLogger("datastore", cnf)
	store := &dataStore{lg: lg, shards: []*shard{}, WrittenSpans: writtenSpans}

	// If we return an error, close the store.
	defer func() {
		if err != nil {
			store.Close()
			store = nil
		}
	}()

	store.readOpts = levigo.NewReadOptions()
	store.readOpts.SetFillCache(true)
	store.writeOpts = levigo.NewWriteOptions()
	store.writeOpts.SetSync(false)

	// Open all shards
	for idx := range dirs {
		path := dirs[idx] + conf.PATH_SEP + "db"
		var shd *shard
		shd, err = CreateShard(store, cnf, path, clearStored)
		if err != nil {
			lg.Errorf("Error creating shard %s: %s\n", path, err.Error())
			return nil, err
		}
		store.shards = append(store.shards, shd)
	}
	for idx := range store.shards {
		shd := store.shards[idx]
		shd.exited = make(chan bool, 1)
		go shd.processIncoming()
	}
	return store, nil
}
Example #10
0
// Create a new datastore loader.
// Initializes the loader, but does not load any leveldb instances.
func NewDataStoreLoader(cnf *conf.Config) *DataStoreLoader {
	dld := &DataStoreLoader{
		lg:          common.NewLogger("datastore", cnf),
		ClearStored: cnf.GetBool(conf.HTRACE_DATA_STORE_CLEAR),
	}
	dld.readOpts = levigo.NewReadOptions()
	dld.readOpts.SetFillCache(true)
	dld.readOpts.SetVerifyChecksums(false)
	dld.writeOpts = levigo.NewWriteOptions()
	dld.writeOpts.SetSync(false)
	dirsStr := cnf.Get(conf.HTRACE_DATA_STORE_DIRECTORIES)
	rdirs := strings.Split(dirsStr, conf.PATH_LIST_SEP)
	// Filter out empty entries
	dirs := make([]string, 0, len(rdirs))
	for i := range rdirs {
		if strings.TrimSpace(rdirs[i]) != "" {
			dirs = append(dirs, rdirs[i])
		}
	}
	dld.shards = make([]*ShardLoader, len(dirs))
	for i := range dirs {
		dld.shards[i] = &ShardLoader{
			dld:  dld,
			path: dirs[i] + conf.PATH_SEP + "db",
		}
	}
	dld.openOpts = levigo.NewOptions()
	cacheSize := cnf.GetInt(conf.HTRACE_LEVELDB_CACHE_SIZE)
	dld.openOpts.SetCache(levigo.NewLRUCache(cacheSize))
	dld.openOpts.SetParanoidChecks(false)
	writeBufferSize := cnf.GetInt(conf.HTRACE_LEVELDB_WRITE_BUFFER_SIZE)
	if writeBufferSize > 0 {
		dld.openOpts.SetWriteBufferSize(writeBufferSize)
	}
	maxFdPerShard := dld.calculateMaxOpenFilesPerShard()
	if maxFdPerShard > 0 {
		dld.openOpts.SetMaxOpenFiles(maxFdPerShard)
	}
	return dld
}
func TestHeartbeaterSendsHeartbeats(t *testing.T) {
	cnfBld := conf.Builder{
		Values:   conf.TEST_VALUES(),
		Defaults: conf.DEFAULTS,
	}
	cnf, err := cnfBld.Build()
	if err != nil {
		t.Fatalf("failed to create conf: %s", err.Error())
	}
	lg := common.NewLogger("heartbeater", cnf)
	// The minimum amount of time which the heartbeater test should take
	MINIMUM_TEST_DURATION := time.Millisecond * (NUM_TEST_HEARTBEATS * HEARTBEATER_PERIOD)
	duration := MINIMUM_TEST_DURATION
	for duration <= MINIMUM_TEST_DURATION {
		start := time.Now()
		testHeartbeaterSendsHeartbeatsImpl(t, lg)
		end := time.Now()
		duration = end.Sub(start)
		lg.Debugf("Measured duration: %v; minimum expected duration: %v\n",
			duration, MINIMUM_TEST_DURATION)
	}
}
Example #12
0
func main() {
	for idx := range os.Args {
		arg := os.Args[idx]
		if strings.HasPrefix(arg, "--h") || strings.HasPrefix(arg, "-h") {
			fmt.Fprintf(os.Stderr, USAGE)
			os.Exit(0)
		}
	}

	// Load the htraced configuration.
	cnf, cnfLog := conf.LoadApplicationConfig("htraced.")

	// Open the HTTP port.
	// We want to do this first, before initializing the datastore or setting up
	// logging.  That way, if someone accidentally starts two daemons with the
	// same config file, the second invocation will exit with a "port in use"
	// error rather than potentially disrupting the first invocation.
	rstListener, listenErr := net.Listen("tcp", cnf.Get(conf.HTRACE_WEB_ADDRESS))
	if listenErr != nil {
		fmt.Fprintf(os.Stderr, "Error opening HTTP port: %s\n",
			listenErr.Error())
		os.Exit(1)
	}

	// Print out the startup banner and information about the daemon
	// configuration.
	lg := common.NewLogger("main", cnf)
	defer lg.Close()
	lg.Infof("*** Starting htraced %s [%s]***\n", RELEASE_VERSION, GIT_VERSION)
	scanner := bufio.NewScanner(cnfLog)
	for scanner.Scan() {
		lg.Infof(scanner.Text() + "\n")
	}
	common.InstallSignalHandlers(cnf)
	if runtime.GOMAXPROCS(0) == 1 {
		ncpu := runtime.NumCPU()
		runtime.GOMAXPROCS(ncpu)
		lg.Infof("setting GOMAXPROCS=%d\n", ncpu)
	} else {
		lg.Infof("GOMAXPROCS=%d\n", runtime.GOMAXPROCS(0))
	}
	lg.Infof("leveldb version=%d.%d\n",
		levigo.GetLevelDBMajorVersion(), levigo.GetLevelDBMinorVersion())

	// Initialize the datastore.
	store, err := CreateDataStore(cnf, nil)
	if err != nil {
		lg.Errorf("Error creating datastore: %s\n", err.Error())
		os.Exit(1)
	}
	var rsv *RestServer
	rsv, err = CreateRestServer(cnf, store, rstListener)
	if err != nil {
		lg.Errorf("Error creating REST server: %s\n", err.Error())
		os.Exit(1)
	}
	var hsv *HrpcServer
	if cnf.Get(conf.HTRACE_HRPC_ADDRESS) != "" {
		hsv, err = CreateHrpcServer(cnf, store, nil)
		if err != nil {
			lg.Errorf("Error creating HRPC server: %s\n", err.Error())
			os.Exit(1)
		}
	} else {
		lg.Infof("Not starting HRPC server because no value was given for %s.\n",
			conf.HTRACE_HRPC_ADDRESS)
	}
	naddr := cnf.Get(conf.HTRACE_STARTUP_NOTIFICATION_ADDRESS)
	if naddr != "" {
		notif := StartupNotification{
			HttpAddr:  rsv.Addr().String(),
			ProcessId: os.Getpid(),
		}
		if hsv != nil {
			notif.HrpcAddr = hsv.Addr().String()
		}
		err = sendStartupNotification(naddr, &notif)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to send startup notification: "+
				"%s\n", err.Error())
			os.Exit(1)
		}
	}
	for {
		time.Sleep(time.Duration(10) * time.Hour)
	}
}
func (bld *MiniHTracedBuilder) Build() (*MiniHTraced, error) {
	var err error
	var store *dataStore
	var rsv *RestServer
	var hsv *HrpcServer
	if bld.Name == "" {
		bld.Name = "HTraceTest"
	}
	if bld.Cnf == nil {
		bld.Cnf = make(map[string]string)
	}
	if bld.DataDirs == nil {
		bld.DataDirs = make([]string, 2)
	}
	for idx := range bld.DataDirs {
		if bld.DataDirs[idx] == "" {
			bld.DataDirs[idx], err = ioutil.TempDir(os.TempDir(),
				fmt.Sprintf("%s%d", bld.Name, idx+1))
			if err != nil {
				return nil, err
			}
		}
	}
	// Copy the default test configuration values.
	for k, v := range conf.TEST_VALUES() {
		_, hasVal := bld.Cnf[k]
		if !hasVal {
			bld.Cnf[k] = v
		}
	}
	bld.Cnf[conf.HTRACE_DATA_STORE_DIRECTORIES] =
		strings.Join(bld.DataDirs, conf.PATH_LIST_SEP)
	cnfBld := conf.Builder{Values: bld.Cnf, Defaults: conf.DEFAULTS}
	cnf, err := cnfBld.Build()
	if err != nil {
		return nil, err
	}
	lg := common.NewLogger("mini.htraced", cnf)
	defer func() {
		if err != nil {
			if store != nil {
				store.Close()
			}
			for idx := range bld.DataDirs {
				if !bld.KeepDataDirsOnClose {
					if bld.DataDirs[idx] != "" {
						os.RemoveAll(bld.DataDirs[idx])
					}
				}
			}
			if rsv != nil {
				rsv.Close()
			}
			lg.Infof("Failed to create MiniHTraced %s: %s\n", bld.Name, err.Error())
			lg.Close()
		}
	}()
	store, err = CreateDataStore(cnf, bld.WrittenSpans)
	if err != nil {
		return nil, err
	}
	rstListener, listenErr := net.Listen("tcp", cnf.Get(conf.HTRACE_WEB_ADDRESS))
	if listenErr != nil {
		return nil, listenErr
	}
	defer func() {
		if rstListener != nil {
			rstListener.Close()
		}
	}()
	rsv, err = CreateRestServer(cnf, store, rstListener)
	if err != nil {
		return nil, err
	}
	rstListener = nil
	hsv, err = CreateHrpcServer(cnf, store, bld.HrpcTestHooks)
	if err != nil {
		return nil, err
	}

	lg.Infof("Created MiniHTraced %s\n", bld.Name)
	return &MiniHTraced{
		Name:                bld.Name,
		Cnf:                 cnf,
		DataDirs:            bld.DataDirs,
		Store:               store,
		Rsv:                 rsv,
		Hsv:                 hsv,
		Lg:                  lg,
		KeepDataDirsOnClose: bld.KeepDataDirsOnClose,
	}, nil
}
Example #14
0
func main() {
	// Load htraced configuration
	cnf, cnfLog := conf.LoadApplicationConfig("htrace.tool.")
	lg := common.NewLogger("conf", cnf)
	defer lg.Close()
	scanner := bufio.NewScanner(cnfLog)
	for scanner.Scan() {
		lg.Debugf(scanner.Text() + "\n")
	}

	// Parse argv
	app := kingpin.New(os.Args[0], USAGE)
	app.Flag("Dmy.key", "Set configuration key 'my.key' to 'my.value'.  Replace 'my.key' "+
		"with any key you want to set.").Default("my.value").String()
	addr := app.Flag("addr", "Server address.").String()
	verbose = *app.Flag("verbose", "Verbose.").Default("false").Bool()
	version := app.Command("version", "Print the version of this program.")
	serverVersion := app.Command("serverVersion", "Print the version of the htraced server.")
	serverStats := app.Command("serverStats", "Print statistics retrieved from the htraced server.")
	serverStatsJson := serverStats.Flag("json", "Display statistics as raw JSON.").Default("false").Bool()
	serverDebugInfo := app.Command("serverDebugInfo", "Print the debug info of the htraced server.")
	serverConf := app.Command("serverConf", "Print the server configuration retrieved from the htraced server.")
	findSpan := app.Command("findSpan", "Print information about a trace span with a given ID.")
	findSpanId := findSpan.Arg("id", "Span ID to find. Example: be305e54-4534-2110-a0b2-e06b9effe112").Required().String()
	findChildren := app.Command("findChildren", "Print out the span IDs that are children of a given span ID.")
	parentSpanId := findChildren.Arg("id", "Span ID to print children for. Example: be305e54-4534-2110-a0b2-e06b9effe112").
		Required().String()
	childLim := findChildren.Flag("lim", "Maximum number of child IDs to print.").Default("20").Int()
	loadFile := app.Command("loadFile", "Write whitespace-separated JSON spans from a file to the server.")
	loadFilePath := loadFile.Arg("path",
		"A file containing whitespace-separated span JSON.").Required().String()
	loadJson := app.Command("load", "Write JSON spans from the command-line to the server.")
	loadJsonArg := loadJson.Arg("json", "A JSON span to write to the server.").Required().String()
	dumpAll := app.Command("dumpAll", "Dump all spans from the htraced daemon.")
	dumpAllOutPath := dumpAll.Arg("path", "The path to dump the trace spans to.").Default("-").String()
	dumpAllLim := dumpAll.Flag("lim", "The number of spans to transfer from the server at once.").
		Default("100").Int()
	graph := app.Command("graph", "Visualize span JSON as a graph.")
	graphJsonFile := graph.Arg("input", "The JSON file to load").Required().String()
	graphDotFile := graph.Flag("output",
		"The path to write a GraphViz dotfile to.  This file can be used as input to "+
			"GraphViz, in order to generate a pretty picture.  See graphviz.org for more "+
			"information about generating pictures of graphs.").Default("-").String()
	query := app.Command("query", "Send a query to htraced.")
	queryLim := query.Flag("lim", "Maximum number of spans to retrieve.").Default("20").Int()
	queryArg := query.Arg("query", "The query string to send.  Query strings have the format "+
		"[TYPE] [OPERATOR] [CONST], joined by AND statements.").Required().String()
	rawQuery := app.Command("rawQuery", "Send a raw JSON query to htraced.")
	rawQueryArg := rawQuery.Arg("json", "The query JSON to send.").Required().String()
	cmd := kingpin.MustParse(app.Parse(os.Args[1:]))

	// Add the command-line settings into the configuration.
	if *addr != "" {
		cnf = cnf.Clone(conf.HTRACE_WEB_ADDRESS, *addr)
	}

	// Handle commands that don't require an HTrace client.
	switch cmd {
	case version.FullCommand():
		os.Exit(printVersion())
	case graph.FullCommand():
		err := jsonSpanFileToDotFile(*graphJsonFile, *graphDotFile)
		if err != nil {
			fmt.Printf("graphing error: %s\n", err.Error())
			os.Exit(EXIT_FAILURE)
		}
		os.Exit(EXIT_SUCCESS)
	}

	// Create HTrace client
	hcl, err := htrace.NewClient(cnf, nil)
	if err != nil {
		fmt.Printf("Failed to create HTrace client: %s\n", err.Error())
		os.Exit(EXIT_FAILURE)
	}

	// Handle commands that require an HTrace client.
	switch cmd {
	case version.FullCommand():
		os.Exit(printVersion())
	case serverVersion.FullCommand():
		os.Exit(printServerVersion(hcl))
	case serverStats.FullCommand():
		if *serverStatsJson {
			os.Exit(printServerStatsJson(hcl))
		} else {
			os.Exit(printServerStats(hcl))
		}
	case serverDebugInfo.FullCommand():
		os.Exit(printServerDebugInfo(hcl))
	case serverConf.FullCommand():
		os.Exit(printServerConfJson(hcl))
	case findSpan.FullCommand():
		var id *common.SpanId
		id.FromString(*findSpanId)
		os.Exit(doFindSpan(hcl, *id))
	case findChildren.FullCommand():
		var id *common.SpanId
		id.FromString(*parentSpanId)
		os.Exit(doFindChildren(hcl, *id, *childLim))
	case loadJson.FullCommand():
		os.Exit(doLoadSpanJson(hcl, *loadJsonArg))
	case loadFile.FullCommand():
		os.Exit(doLoadSpanJsonFile(hcl, *loadFilePath))
	case dumpAll.FullCommand():
		err := doDumpAll(hcl, *dumpAllOutPath, *dumpAllLim)
		if err != nil {
			fmt.Printf("dumpAll error: %s\n", err.Error())
			os.Exit(EXIT_FAILURE)
		}
		os.Exit(EXIT_SUCCESS)
	case query.FullCommand():
		err := doQueryFromString(hcl, *queryArg, *queryLim)
		if err != nil {
			fmt.Printf("query error: %s\n", err.Error())
			os.Exit(EXIT_FAILURE)
		}
		os.Exit(EXIT_SUCCESS)
	case rawQuery.FullCommand():
		err := doRawQuery(hcl, *rawQueryArg)
		if err != nil {
			fmt.Printf("raw query error: %s\n", err.Error())
			os.Exit(EXIT_FAILURE)
		}
		os.Exit(EXIT_SUCCESS)
	}

	app.UsageErrorf(os.Stderr, "You must supply a command to run.")
}
Example #15
0
func (bld *MiniHTracedBuilder) Build() (*MiniHTraced, error) {
	var err error
	var store *dataStore
	var rsv *RestServer
	var hsv *HrpcServer
	if bld.Name == "" {
		bld.Name = "HTraceTest"
	}
	if bld.Cnf == nil {
		bld.Cnf = make(map[string]string)
	}
	if bld.DataDirs == nil {
		bld.DataDirs = make([]string, 2)
	}
	for idx := range bld.DataDirs {
		if bld.DataDirs[idx] == "" {
			bld.DataDirs[idx], err = ioutil.TempDir(os.TempDir(),
				fmt.Sprintf("%s%d", bld.Name, idx+1))
			if err != nil {
				return nil, err
			}
		}
	}
	bld.Cnf[conf.HTRACE_DATA_STORE_DIRECTORIES] =
		strings.Join(bld.DataDirs, conf.PATH_LIST_SEP)
	bld.Cnf[conf.HTRACE_WEB_ADDRESS] = ":0"  // use a random port for the REST server
	bld.Cnf[conf.HTRACE_HRPC_ADDRESS] = ":0" // use a random port for the HRPC server
	bld.Cnf[conf.HTRACE_LOG_LEVEL] = "TRACE"
	cnfBld := conf.Builder{Values: bld.Cnf, Defaults: conf.DEFAULTS}
	cnf, err := cnfBld.Build()
	if err != nil {
		return nil, err
	}
	lg := common.NewLogger("mini.htraced", cnf)
	defer func() {
		if err != nil {
			if store != nil {
				store.Close()
			}
			for idx := range bld.DataDirs {
				if bld.DataDirs[idx] != "" {
					os.RemoveAll(bld.DataDirs[idx])
				}
			}
			if rsv != nil {
				rsv.Close()
			}
			lg.Infof("Failed to create MiniHTraced %s: %s\n", bld.Name, err.Error())
			lg.Close()
		}
	}()
	store, err = CreateDataStore(cnf, bld.WrittenSpans)
	if err != nil {
		return nil, err
	}
	rsv, err = CreateRestServer(cnf, store)
	if err != nil {
		return nil, err
	}
	hsv, err = CreateHrpcServer(cnf, store)
	if err != nil {
		return nil, err
	}

	lg.Infof("Created MiniHTraced %s\n", bld.Name)
	return &MiniHTraced{
		Name:                bld.Name,
		Cnf:                 cnf,
		DataDirs:            bld.DataDirs,
		Store:               store,
		Rsv:                 rsv,
		Hsv:                 hsv,
		Lg:                  lg,
		KeepDataDirsOnClose: bld.KeepDataDirsOnClose,
	}, nil
}