blob: 024d97339a55b75abd8ccee0a6300c441c02da6a [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"
"errors"
"fmt"
"io"
"org/apache/htrace/common"
"os"
"sort"
)
// Create a dotfile from a json file.
func jsonSpanFileToDotFile(jsonFile string, dotFile string) error {
spans, err := readSpansFile(jsonFile)
if err != nil {
return errors.New(fmt.Sprintf("error reading %s: %s",
jsonFile, err.Error()))
}
var file *OutputFile
file, err = CreateOutputFile(dotFile)
if err != nil {
return errors.New(fmt.Sprintf("error opening %s for write: %s",
dotFile, err.Error()))
}
defer func() {
if file != nil {
file.Close()
}
}()
writer := bufio.NewWriter(file)
err = spansToDot(spans, writer)
if err != nil {
return err
}
err = writer.Flush()
if err != nil {
return err
}
err = file.Close()
file = nil
return err
}
// Create output in dotfile format from a set of spans.
func spansToDot(spans common.SpanSlice, writer io.Writer) error {
sort.Sort(spans)
idMap := make(map[[16]byte]*common.Span)
for i := range spans {
span := spans[i]
if idMap[span.Id.ToArray()] != nil {
fmt.Fprintf(os.Stderr, "There were multiple spans listed which "+
"had ID %s.\nFirst:%s\nOther:%s\n", span.Id.String(),
idMap[span.Id.ToArray()].ToJson(), span.ToJson())
} else {
idMap[span.Id.ToArray()] = span
}
}
childMap := make(map[[16]byte]common.SpanSlice)
for i := range spans {
child := spans[i]
for j := range child.Parents {
parent := idMap[child.Parents[j].ToArray()]
if parent == nil {
fmt.Fprintf(os.Stderr, "Can't find parent id %s for %s\n",
child.Parents[j].String(), child.ToJson())
} else {
children := childMap[parent.Id.ToArray()]
if children == nil {
children = make(common.SpanSlice, 0)
}
children = append(children, child)
childMap[parent.Id.ToArray()] = children
}
}
}
w := NewFailureDeferringWriter(writer)
w.Printf("digraph spans {\n")
// Write out the nodes with their descriptions.
for i := range spans {
w.Printf(fmt.Sprintf(` "%s" [label="%s"];`+"\n",
spans[i].Id.String(), spans[i].Description))
}
// Write out the edges between nodes... the parent/children relationships
for i := range spans {
children := childMap[spans[i].Id.ToArray()]
sort.Sort(children)
if children != nil {
for c := range children {
w.Printf(fmt.Sprintf(` "%s" -> "%s";`+"\n",
spans[i].Id.String(), children[c].Id))
}
}
}
w.Printf("}\n")
return w.Error()
}