blob: f1e765f09951770bde6063decb780386a9c65065 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 main
import (
"bufio"
"encoding/json"
"fmt"
"github.com/alecthomas/kingpin"
"io"
htrace "org/apache/htrace/client"
"org/apache/htrace/common"
"org/apache/htrace/conf"
"os"
)
var RELEASE_VERSION string
var GIT_VERSION string
const EXIT_SUCCESS = 0
const EXIT_FAILURE = 1
var verbose *bool
const USAGE = `The Apache HTrace command-line tool. This tool retrieves and modifies settings and
other data on a running htraced daemon.
If we find an ` + conf.CONFIG_FILE_NAME + ` configuration file in the list of directories
specified in ` + conf.HTRACED_CONF_DIR + `, we will use that configuration; otherwise,
the defaults will be used.
`
func main() {
// Load htraced configuration
cnf := conf.LoadApplicationConfig()
// 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.")
serverInfo := app.Command("serverInfo", "Print information retrieved from an 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: 0x123456789abcdef").Required().Uint64()
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: 0x123456789abcdef").
Required().Uint64()
childLim := findChildren.Flag("lim", "Maximum number of child IDs to print.").Default("20").Int()
writeSpans := app.Command("writeSpans", "Write spans to the server in JSON form.")
spanJson := writeSpans.Flag("json", "The JSON span data to write to the server.").String()
spanFile := writeSpans.Flag("file",
"A file containing JSON span data to write to the server.").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)
}
// Create HTrace client
hcl, err := htrace.NewClient(cnf)
if err != nil {
fmt.Printf("Failed to create HTrace client: %s\n", err.Error())
os.Exit(EXIT_FAILURE)
}
// Handle operation
switch cmd {
case version.FullCommand():
os.Exit(printVersion())
case serverInfo.FullCommand():
os.Exit(printServerInfo(hcl))
case findSpan.FullCommand():
os.Exit(doFindSpan(hcl, common.SpanId(*findSpanId)))
case findChildren.FullCommand():
os.Exit(doFindChildren(hcl, common.SpanId(*parentSpanId), *childLim))
case writeSpans.FullCommand():
if *spanJson != "" {
if *spanFile != "" {
fmt.Printf("You must specify either --json or --file, " +
"but not both.\n")
os.Exit(EXIT_FAILURE)
}
os.Exit(doWriteSpanJson(hcl, *spanJson))
} else if *spanFile != "" {
os.Exit(doWriteSpanJsonFile(hcl, *spanFile))
}
fmt.Printf("You must specify either --json or --file.\n")
os.Exit(EXIT_FAILURE)
}
app.UsageErrorf(os.Stderr, "You must supply a command to run.")
}
// Print the version of the htrace binary.
func printVersion() int {
fmt.Printf("Running htrace command version %s.\n", RELEASE_VERSION)
return EXIT_SUCCESS
}
// Print information retrieved from an htraced server via /server/info
func printServerInfo(hcl *htrace.Client) int {
info, err := hcl.GetServerInfo()
if err != nil {
fmt.Println(err.Error())
return EXIT_FAILURE
}
fmt.Printf("HTraced server version %s (%s)\n", info.ReleaseVersion, info.GitVersion)
return EXIT_SUCCESS
}
// Print information about a trace span.
func doFindSpan(hcl *htrace.Client, sid common.SpanId) int {
span, err := hcl.FindSpan(sid)
if err != nil {
fmt.Println(err.Error())
return EXIT_FAILURE
}
if span == nil {
fmt.Printf("Span ID not found.\n")
return EXIT_FAILURE
}
pbuf, err := json.MarshalIndent(span, "", " ")
if err != nil {
fmt.Printf("Error: error pretty-printing span to JSON: %s\n", err.Error())
return EXIT_FAILURE
}
fmt.Printf("%s\n", string(pbuf))
return EXIT_SUCCESS
}
func doWriteSpanJsonFile(hcl *htrace.Client, spanFile string) int {
file, err := os.Open(spanFile)
if err != nil {
fmt.Printf("Failed to open %s: %s\n", spanFile, err.Error())
return EXIT_FAILURE
}
defer file.Close()
in := bufio.NewReader(file)
dec := json.NewDecoder(in)
for {
var span common.Span
if err = dec.Decode(&span); err != nil {
if err == io.EOF {
break
}
fmt.Println("Failed to decode JSON: %s", err.Error())
return EXIT_FAILURE
}
if *verbose {
fmt.Printf("wrote %s\n", span.ToJson())
}
if err = hcl.WriteSpan(&span); err != nil {
fmt.Println(err.Error())
return EXIT_FAILURE
}
}
return EXIT_SUCCESS
}
func doWriteSpanJson(hcl *htrace.Client, spanJson string) int {
spanBytes := []byte(spanJson)
var span common.Span
err := json.Unmarshal(spanBytes, &span)
if err != nil {
fmt.Printf("Error parsing provided JSON: %s\n", err.Error())
return EXIT_FAILURE
}
err = hcl.WriteSpan(&span)
if err != nil {
fmt.Println(err.Error())
return EXIT_FAILURE
}
return EXIT_SUCCESS
}
// Find information about the children of a span.
func doFindChildren(hcl *htrace.Client, sid common.SpanId, lim int) int {
spanIds, err := hcl.FindChildren(sid, lim)
if err != nil {
fmt.Printf("%s\n", err.Error())
return EXIT_FAILURE
}
pbuf, err := json.MarshalIndent(spanIds, "", " ")
if err != nil {
fmt.Println("Error: error pretty-printing span IDs to JSON: %s", err.Error())
return 1
}
fmt.Printf("%s\n", string(pbuf))
return 0
}