incubator-htrace-3.1.0/000077500000000000000000000000001245601110500147405ustar00rootroot00000000000000incubator-htrace-3.1.0/.gitignore000066400000000000000000000004101245601110500167230ustar00rootroot00000000000000.project *.settings/ .classpath /.idea/ /logs *target/ *.iml *.orig *~ *.swp dependency-reduced-pom.xml htrace-core/src/go/src/org/apache/htrace/resource !htrace-core/src/go/src/org/apache/htrace/resource/catalog.go htrace-core/src/go/build htrace-core/src/go/pkg incubator-htrace-3.1.0/BUILDING.txt000066400000000000000000000006571245601110500167060ustar00rootroot00000000000000On Building HTrace Requires go version 1.3.1 or 1.4. Also requires godep. See hbase-core/src/go/BUILDING.txt for more. Requires Java 1.7 at least. Requires maven 3.x. After installing go, to build, run: $ mvn install To build a tarball, do: $ mvn clean install -DskipTests assembly:single This will build a tarball into ./target. To skip the rat-check -- it can take a while -- pass a -Drat.skip on the mvn command-line. incubator-htrace-3.1.0/DISCLAIMER.txt000066400000000000000000000010351245601110500171140ustar00rootroot00000000000000Apache HTrace is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the Apache Incubator project. Incubation is required of all newly accepted projects until a further review indicates that the infrastructure, communications, and decision making process have stabilized in a manner consistent with other successful ASF projects. While incubation status is not necessarily a reflection of the completeness or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF. incubator-htrace-3.1.0/LICENSE.txt000066400000000000000000000320651245601110500165710ustar00rootroot00000000000000Apache HTrace (incubating) is Apache 2.0 Licensed. See below for licensing of dependencies that are NOT Apache Licensed. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. levigo, a go wrapper for leveldb, is Copyright (c) 2012 Jeffrey M Hodges and MIT licensed: https://github.com/jmhodges/levigo/blob/master/LICENSE Kingpin, a go command line and flag parser, is Copyright (c) 2014 Alec Thomas and MIT licensed: https://github.com/alecthomas/kingpin/blob/master/COPYING Units, a string formatting go library, is Copyright (c) 2014 Alec Thomas and MIT licensed: https://github.com/alecthomas/units/blob/master/COPYING D3, a javascript library for manipulating data, used by htrace-hbase is Copyright 2010-2014, Michael Bostock and BSD licensed: https://github.com/mbostock/d3/blob/master/LICENSE Bootstrap, an html, css, and javascript framework, is Copyright (c) 2011-2015 Twitter, Inc and MIT licensed: https://github.com/twbs/bootstrap/blob/master/LICENSE Gorilla mux gorilla/mux implements a request router and dispatcher is BSD licensed: https://github.com/gorilla/mux/blob/master/LICENSE godep, a build dependency is Copyright © 2013 Keith Rarick and portions Copyright (c) 2012 The Go Authors. Its a BSD license: https://github.com/tools/godep/blob/master/License underscore, a javascript library of functional programming helpers, is (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors and an MIT license: https://github.com/jashkenas/underscore/blob/master/LICENSE jquery, a javascript library, is Copyright jQuery Foundation and other contributors, https://jquery.org/. The software consists of voluntary contributions made by many individuals. For exact contribution history, see the revision history available at https://github.com/jquery/jquery It is MIT licensed: https://github.com/jquery/jquery/blob/master/LICENSE.txt backbone, is a javascript library, that is Copyright (c) 2010-2014 Jeremy Ashkenas, DocumentCloud. It is MIT licensed: https://github.com/jashkenas/backbone/blob/master/LICENSE incubator-htrace-3.1.0/NOTICE.txt000066400000000000000000000007001245601110500164570ustar00rootroot00000000000000This product includes software developed by The Apache Software Foundation (http://www.apache.org/). In addition, this product includes software dependencies. See the accompanying LICENSE.txt for a listing of dependencies that are NOT Apache licensed (with pointers to their licensing) Apache HTrace includes an Apache Thrift connector to Zipkin. Zipkin is a distributed tracing system that is Apache 2.0 Licensed. Copyright 2012 Twitter, Inc. incubator-htrace-3.1.0/README.md000066400000000000000000000017071245601110500162240ustar00rootroot00000000000000 HTrace ====== HTrace is a tracing framework for use with distributed systems written in java. See documentation at src/main/site/markdown/index.md or at http://htrace.incubator.apache.org. incubator-htrace-3.1.0/bin/000077500000000000000000000000001245601110500155105ustar00rootroot00000000000000incubator-htrace-3.1.0/bin/gen_thrift.sh000077500000000000000000000021061245601110500201770ustar00rootroot00000000000000# #/** # * Copyright 2007 The Apache Software Foundation # * # * 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. # */ SOURCE="${BASH_SOURCE[0]}" DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" cd $DIR/../ FILES=htrace-zipkin/src/main/thrift/* for FILE in $FILES do thrift --gen java -out htrace-zipkin/src/main/java $FILE done incubator-htrace-3.1.0/htrace-core/000077500000000000000000000000001245601110500171345ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/pom.xml000066400000000000000000000133061245601110500204540ustar00rootroot00000000000000 4.0.0 htrace-core jar htrace org.apache.htrace 3.1.0-incubating .. htrace-core http://incubator.apache.org/projects/htrace.html UTF-8 maven-assembly-plugin true org.apache.maven.plugins maven-source-plugin maven-javadoc-plugin maven-compiler-plugin org.apache.maven.plugins maven-shade-plugin package org.apache.commons.logging org.apache.htrace.commons.logging com.fasterxml.jackson org.apache.htrace.fasterxml.jackson shade org.apache.maven.plugins maven-antrun-plugin compile go_compile run test go_test run clean go_clean run org.apache.maven.plugins maven-gpg-plugin org.apache.maven.plugins maven-jar-plugin org.apache.rat apache-rat-plugin maven-deploy-plugin junit junit test commons-logging commons-logging com.fasterxml.jackson.core jackson-core 2.4.0 com.fasterxml.jackson.core jackson-databind 2.4.0 incubator-htrace-3.1.0/htrace-core/src/000077500000000000000000000000001245601110500177235ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/000077500000000000000000000000001245601110500203305ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/BUILDING.txt000066400000000000000000000022451245601110500222710ustar00rootroot00000000000000Building the HTrace Go code =========================== The htrace go code consists of 4 main parts: * The "htraced" standalone server This is a server which accepts trace spans, and services REST queries. * The "htrace" command-line program which can query the server This is a simple command-line program which can query the htrace server. * The htraced Javascript Web UI (not yet implemented) * The htrace go client library (not yet implemented) This is the equivalent of the Java HTrace client library, but written in Go. You can build all these parts simply by running "gobuild.sh". The binaries will be created in bin/. Dependencies ============ You will need to install: * The Go programming language * The development package for leveldb (some Linux distros call this "leveldb-devel") containing libleveldb.so * Version 0 of the "godep" tool from https://github.com/tools/godep/releases htraced requires libleveldb.so to be in your shared library path in order to run. You can set LD_LIBRARY_PATH to the path for this library, or simply install libleveldb.so to your system library path. Testing ======= You can run the unit tests by running "./gobuild.sh test" incubator-htrace-3.1.0/htrace-core/src/go/Godeps/000077500000000000000000000000001245601110500215515ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/Godeps/Godeps.json000066400000000000000000000014641245601110500236720ustar00rootroot00000000000000{ "ImportPath": "git-wip-us.apache.org/repos/asf/incubator-htrace.git", "GoVersion": "go1.3.1", "Deps": [ { "ImportPath": "github.com/alecthomas/kingpin", "Rev": "afafa8aab106d31c9dc8f5e562b3f30f6246c3d4" }, { "ImportPath": "github.com/alecthomas/units", "Rev": "6b4e7dc5e3143b85ea77909c72caf89416fc2915" }, { "ImportPath": "github.com/gorilla/context", "Rev": "215affda49addc4c8ef7e2534915df2c8c35c6cd" }, { "ImportPath": "github.com/gorilla/mux", "Rev": "e444e69cbd2e2e3e0749a2f3c717cec491552bbf" }, { "ImportPath": "github.com/jmhodges/levigo", "Rev": "2c43dde93d0e056173706534afd514fcbc1dd578" } ] } incubator-htrace-3.1.0/htrace-core/src/go/format.sh000077500000000000000000000024451245601110500221640ustar00rootroot00000000000000#!/usr/bin/env bash # # 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. # # # Reformats the HTrace code. # # ./format.sh Reformats all code. # die() { echo $@ exit 1 } # Check for gofmt. It should be installed whenever the go developement tools # are installed. which gofmt &> /dev/null [ $? -ne 0 ] && die "You must install the gofmt code reformatting formatting tool." # Find go sources. We assume no newlines or whitespace in file names. SCRIPT_DIR="$(cd "$( dirname $0 )" && pwd)" find "${SCRIPT_DIR}" -noleaf -xdev -name '*.go' | xargs -l gofmt -w incubator-htrace-3.1.0/htrace-core/src/go/gobuild.sh000077500000000000000000000066251245601110500223250ustar00rootroot00000000000000#!/usr/bin/env bash # # 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. # # # Builds the HTrace server code. # # ./build.sh Builds the code. # ./build.sh test Builds and runs all unit tests. # ./build.sh bench Builds and runs all benchmarks # die() { echo $@ exit 1 } ACTION=install if [ $# -gt 0 ]; then ACTION="${1}" shift fi RELEASE_VERSION=${RELEASE_VERSION:-unknown} # Set up directories. The build/ directory is where build dependencies and # build binaries should go. SCRIPT_DIR="$(cd "$( dirname $0 )" && pwd)" export GOBIN="${SCRIPT_DIR}/build" mkdir -p "${GOBIN}" || die "failed to mkdir -p ${GOBIN}" cd "${GOBIN}" || die "failed to cd to ${SCRIPT_DIR}" export GOPATH="${GOBIN}:${SCRIPT_DIR}" # Check for go which go &> /dev/null if [ $? -ne 0 ]; then cat < /dev/null [ $? -eq 0 ] && ldconfig=ldconfig fi if [ -n "${ldconfig}" ]; then if "${ldconfig}" -p | grep -q libleveldb; then : else echo "You must install the leveldb-devel package (or distro-specific equivalent.)" exit 1 fi fi case $ACTION in clean) rm -rf -- "${GOBIN}" ${SCRIPT_DIR}/pkg find "${SCRIPT_DIR}/src/org/apache/htrace/resource" ! -name 'catalog.go' \ -type f -exec rm -f {} + ;; install) # Ensure that we have the godep program. PATH="${PATH}:${GOBIN}" which godep &> /dev/null if [ $? -ne 0 ]; then echo "Installing godep..." go get github.com/tools/godep || die "failed to get godep" fi # Download dependencies into the build directory. echo "godep restore..." godep restore || die "failed to set up dependencies" go run "$SCRIPT_DIR/src/org/apache/htrace/bundler/bundler.go" \ --src="$SCRIPT_DIR/../web/" --dst="$SCRIPT_DIR/src/org/apache/htrace/resource/" \ || die "bundler failed" # Discover the git version GIT_VERSION=$(git rev-parse HEAD) [ $? -eq 0 ] || GIT_VERSION="unknown" # Inject the release and git version into the htraced ldflags. FLAGS="-X main.RELEASE_VERSION ${RELEASE_VERSION} -X main.GIT_VERSION ${GIT_VERSION}" go install -ldflags "${FLAGS}" -v org/apache/htrace/... "$@" ;; bench) go test -v org/apache/htrace/... -test.bench=. "$@" ;; *) go ${ACTION} -v org/apache/htrace/... "$@" ;; esac incubator-htrace-3.1.0/htrace-core/src/go/src/000077500000000000000000000000001245601110500211175ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/000077500000000000000000000000001245601110500217065ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/000077500000000000000000000000001245601110500231275ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/000077500000000000000000000000001245601110500243755ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/bundler/000077500000000000000000000000001245601110500260305ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/bundler/bundler.go000066400000000000000000000136631245601110500300230ustar00rootroot00000000000000/* * 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 // // The bundler turns files into resources contained in go code. // // This is useful for serving HTML and Javascript files from a self-contained binary. // import ( "bufio" "flag" "fmt" "io/ioutil" "log" "os" "path/filepath" "strings" ) const APACHE_HEADER = `/* * 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. */ ` const GENERATED_CODE_COMMENT = "// THIS IS GENERATED CODE. DO NOT EDIT." var SEP string = string(os.PathSeparator) // Return true if a file contains a given string. func fileContainsString(path, line string) (bool, error) { file, err := os.Open(path) if err != nil { return false, err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { if strings.Contains(scanner.Text(), line) { return true, nil } } if err := scanner.Err(); err != nil { return false, err } return false, nil } // Converts a source file path to a destination file path func sfileToDfile(sfile string) string { return strings.Replace(sfile, SEP, "__", -1) + ".go" } // Delete generated files that are in dfiles but not sfiles. // sfiles and dfiles must be sorted by file name. func deleteUnusedDst(sfiles []string, dst string, dfiles []os.FileInfo) error { s := 0 for d := range dfiles { fullDst := dst + SEP + dfiles[d].Name() generated, err := fileContainsString(fullDst, GENERATED_CODE_COMMENT) if err != nil { return err } if !generated { // Skip this destination file, since it is not generated. continue } found := false for { if s >= len(sfiles) { break } tgt := sfileToDfile(sfiles[s]) if tgt == dfiles[d].Name() { found = true break } if tgt > dfiles[d].Name() { break } s++ } if !found { log.Printf("Removing %s\n", fullDst) err := os.Remove(fullDst) if err != nil { return err } } } return nil } func createBundleFile(pkg, src, sfile, dst string) error { // Open destination file and write header. tgt := sfileToDfile(sfile) fullDst := dst + SEP + tgt out, err := os.Create(fullDst) if err != nil { return err } defer out.Close() _, err = out.WriteString(APACHE_HEADER) if err != nil { return err } _, err = out.WriteString("\n" + GENERATED_CODE_COMMENT + "\n") if err != nil { return err } _, err = out.WriteString(fmt.Sprintf("\npackage %s\n", pkg)) if err != nil { return err } _, err = out.WriteString(fmt.Sprintf("var _ = addResource(\"%s\", `\n", tgt[:len(tgt)-3])) if err != nil { return err } // Open source file and create scanner. fullSrc := src + SEP + sfile in, err := os.Open(fullSrc) if err != nil { return err } defer in.Close() reader := bufio.NewReader(in) scanner := bufio.NewScanner(reader) for scanner.Scan() { _, err := out.WriteString(strings.Replace(scanner.Text(), "`", "` + \"`\" + `", -1) + "\n") if err != nil { return err } } _, err = out.WriteString("`)\n") if err != nil { return err } err = out.Close() if err != nil { return err } return nil } var src = flag.String("src", "", "Source path for bundled resources.") var dst = flag.String("dst", "", "Destination path for bundled resources.") var pkg = flag.String("pkg", "resource", "Package name to use for bundled resources") func main() { flag.Parse() if *src == "" { log.Fatal("You must supply a src directory to bundle.") } if *dst == "" { log.Fatal("You must supply a dst directory for output.") } sfiles := make([]string, 0, 32) absSrc, err := filepath.Abs(filepath.Clean(*src)) if err != nil { log.Fatalf("Error getting absolute path for %s: %s\n", *src, err.Error()) } err = filepath.Walk(absSrc, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } var suffix string suffix, err = filepath.Rel(absSrc, path) if err != nil { return err } sfiles = append(sfiles, suffix) return nil }) if err != nil { log.Fatalf("Error listing files in src directory %s: %s\n", absSrc, err.Error()) } var dfiles []os.FileInfo dfiles, err = ioutil.ReadDir(*dst) if err != nil { log.Fatalf("Error listing files in output directory %s: %s\n", *dst, err.Error()) } deleteUnusedDst(sfiles, *dst, dfiles) for s := range sfiles { err = createBundleFile(*pkg, absSrc, sfiles[s], *dst) if err != nil { log.Fatalf("Error creating bundle file for %s in %s: %s\n", sfiles[s], *dst, err.Error()) } log.Printf("Bundled %s as %s\n", absSrc, absSrc+SEP+sfileToDfile(sfiles[s])) } } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/common/000077500000000000000000000000001245601110500256655ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/common/rest.go000066400000000000000000000017631245601110500272000ustar00rootroot00000000000000/* * 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 common // Info returned by /serverInfo type ServerInfo struct { // The server release version. ReleaseVersion string // The git hash that this software was built with. GitVersion string } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/common/span.go000066400000000000000000000046621245601110500271650ustar00rootroot00000000000000/* * 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 common import ( "encoding/json" "fmt" "strconv" ) // // Represents a trace span. // // Compatibility notes: // When converting to JSON, we store the 64-bit numbers as hexadecimal strings rather than as // integers. This is because JavaScript lacks the ability to handle 64-bit integers. Numbers above // about 55 bits will be rounded by Javascript. Since the Javascript UI is a primary consumer of // this JSON data, we have to simply pass it as a string. // type TraceInfoMap map[string][]byte type TimelineAnnotation struct { Time int64 `json:"t"` Msg string `json:"m"` } type SpanId int64 func (id SpanId) String() string { return fmt.Sprintf("%016x", id) } func (id SpanId) Val() int64 { return int64(id) } func (id SpanId) MarshalJSON() ([]byte, error) { return []byte(`"` + fmt.Sprintf("%016x", uint64(id)) + `"`), nil } func (id *SpanId) UnMarshalJSON(b []byte) error { v, err := strconv.ParseUint(string(b), 16, 64) if err != nil { return err } *id = SpanId(v) return nil } type SpanData struct { Begin int64 `json:"b"` End int64 `json:"e"` Description string `json:"d"` TraceId SpanId `json:"i"` Parents []SpanId `json:"p"` Info TraceInfoMap `json:"n,omitempty"` ProcessId string `json:"r"` TimelineAnnotations []TimelineAnnotation `json:"t,omitempty"` } type Span struct { Id SpanId `json:"s,string"` SpanData } func (span *Span) ToJson() []byte { jbytes, err := json.Marshal(*span) if err != nil { panic(err) } return jbytes } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/common/span_test.go000066400000000000000000000037661245601110500302300ustar00rootroot00000000000000/* * 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 common import ( "testing" ) func TestSpanToJson(t *testing.T) { t.Parallel() span := Span{Id: 2305843009213693952, SpanData: SpanData{ Begin: 123, End: 456, Description: "getFileDescriptors", TraceId: 999, Parents: []SpanId{}, ProcessId: "testProcessId", }} ExpectStrEqual(t, `{"s":"2000000000000000","b":123,"e":456,"d":"getFileDescriptors","i":"00000000000003e7","p":[],"r":"testProcessId"}`, string(span.ToJson())) } func TestAnnotatedSpanToJson(t *testing.T) { t.Parallel() span := Span{Id: 1305813009213693952, SpanData: SpanData{ Begin: 1234, End: 4567, Description: "getFileDescriptors2", TraceId: 999, Parents: []SpanId{}, ProcessId: "testAnnotatedProcessId", TimelineAnnotations: []TimelineAnnotation{ TimelineAnnotation{ Time: 7777, Msg: "contactedServer", }, TimelineAnnotation{ Time: 8888, Msg: "passedFd", }, }, }} ExpectStrEqual(t, `{"s":"121f2e036d442000","b":1234,"e":4567,"d":"getFileDescriptors2","i":"00000000000003e7","p":[],"r":"testAnnotatedProcessId","t":[{"t":7777,"m":"contactedServer"},{"t":8888,"m":"passedFd"}]}`, string(span.ToJson())) } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/common/test_util.go000066400000000000000000000041201245601110500302250ustar00rootroot00000000000000/* * 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 common import ( "fmt" "testing" "time" ) type Int64Slice []int64 func (p Int64Slice) Len() int { return len(p) } func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] } func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } type SupplierFun func() bool // // Wait for a configurable amount of time for a precondition to become true. // // Example: // WaitFor(time.Minute * 1, time.Millisecond * 1, func() bool { // return ht.Store.GetStatistics().NumSpansWritten >= 3 // }) // func WaitFor(dur time.Duration, poll time.Duration, fun SupplierFun) { if poll == 0 { poll = dur / 10 } if poll <= 0 { panic("Can't have a polling time less than zero.") } endTime := time.Now().Add(dur) for { if fun() { return } if !time.Now().Before(endTime) { break } time.Sleep(poll) } panic(fmt.Sprintf("Timed out after %s", dur)) } // Trigger a test failure if two strings are not equal. func ExpectStrEqual(t *testing.T, expect string, actual string) { if expect != actual { t.Fatalf("Expected:\n%s\nGot:\n%s\n", expect, actual) } } // Trigger a test failure if the JSON representation of two spans are not equals. func ExpectSpansEqual(t *testing.T, spanA *Span, spanB *Span) { ExpectStrEqual(t, string(spanA.ToJson()), string(spanB.ToJson())) } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/conf/000077500000000000000000000000001245601110500253225ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/conf/config.go000066400000000000000000000116421245601110500271220ustar00rootroot00000000000000/* * 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 conf import ( "bufio" "fmt" "io" "log" "os" "strconv" "strings" "syscall" ) // // The configuration code for HTraced. // // HTraced can be configured via Hadoop-style XML configuration files, or by passing -Dkey=value // command line arguments. Command-line arguments without an equals sign, such as "-Dkey", will be // treated as setting the key to "true". // // Configuration key constants should be defined in config_keys.go. Each key should have a default, // which will be used if the user supplies no value, or supplies an invalid value. // For that reason, it is not necessary for the Get, GetInt, etc. functions to take a default value // argument. // type Config struct { settings map[string]string defaults map[string]string } type Builder struct { // If non-nil, the XML configuration file to read. Reader io.Reader // If non-nil, the configuration values to use. Values map[string]string // If non-nil, the default configuration values to use. Defaults map[string]string // If non-nil, the command-line arguments to use. Argv []string } // Load a configuration from the application's argv, configuration file, and the standard // defaults. func LoadApplicationConfig() *Config { reader, err := openFile(CONFIG_FILE_NAME, []string{"."}) if err != nil { log.Fatal("Error opening config file: " + err.Error()) } bld := Builder{} if reader != nil { defer reader.Close() bld.Reader = bufio.NewReader(reader) } bld.Argv = os.Args[1:] bld.Defaults = DEFAULTS var cnf *Config cnf, err = bld.Build() if err != nil { log.Fatal("Error building configuration: " + err.Error()) } os.Args = append(os.Args[0:1], bld.Argv...) return cnf } // Attempt to open a configuration file somewhere on the provided list of paths. func openFile(cnfName string, paths []string) (io.ReadCloser, error) { for p := range paths { path := fmt.Sprintf("%s%c%s", paths[p], os.PathSeparator, cnfName) file, err := os.Open(path) if err == nil { log.Println("Reading configuration from " + path) return file, nil } if e, ok := err.(*os.PathError); ok && e.Err == syscall.ENOENT { continue } log.Println("Error opening " + path + " for read: " + err.Error()) } return nil, nil } // Build a new configuration object from the provided conf.Builder. func (bld *Builder) Build() (*Config, error) { // Load values and defaults cnf := Config{} cnf.settings = make(map[string]string) if bld.Values != nil { for k, v := range bld.Values { cnf.settings[k] = v } } cnf.defaults = make(map[string]string) if bld.Defaults != nil { for k, v := range bld.Defaults { cnf.defaults[k] = v } } // Process the configuration file, if we have one if bld.Reader != nil { parseXml(bld.Reader, cnf.settings) } // Process command line arguments var i int for i < len(bld.Argv) { str := bld.Argv[i] if strings.HasPrefix(str, "-D") { idx := strings.Index(str, "=") if idx == -1 { key := str[2:] cnf.settings[key] = "true" } else { key := str[2:idx] val := str[idx+1:] cnf.settings[key] = val } bld.Argv = append(bld.Argv[:i], bld.Argv[i+1:]...) } else { i++ } } return &cnf, nil } // Get a string configuration key. func (cnf *Config) Get(key string) string { ret := cnf.settings[key] if ret != "" { return ret } return cnf.defaults[key] } // Get a boolean configuration key. func (cnf *Config) GetBool(key string) bool { str := cnf.settings[key] ret, err := strconv.ParseBool(str) if err == nil { return ret } str = cnf.defaults[key] ret, err = strconv.ParseBool(str) if err == nil { return ret } return false } // Get an integer configuration key. func (cnf *Config) GetInt(key string) int { str := cnf.settings[key] ret, err := strconv.Atoi(str) if err == nil { return ret } str = cnf.defaults[key] ret, err = strconv.Atoi(str) if err == nil { return ret } return 0 } // Get an int64 configuration key. func (cnf *Config) GetInt64(key string) int64 { str := cnf.settings[key] ret, err := strconv.ParseInt(str, 10, 64) if err == nil { return ret } str = cnf.defaults[key] ret, err = strconv.ParseInt(str, 10, 64) if err == nil { return ret } return 0 } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/conf/config_keys.go000066400000000000000000000042501245601110500301520ustar00rootroot00000000000000/* * 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 conf import ( "fmt" "os" ) // // Configuration keys for HTrace. // // The platform-specific path separator. Usually slash. var PATH_SEP string = fmt.Sprintf("%c", os.PathSeparator) // The platform-specific path list separator. Usually colon. var PATH_LIST_SEP string = fmt.Sprintf("%c", os.PathListSeparator) // The name of the XML configuration file to look for. const CONFIG_FILE_NAME = "htraced.xml" // The web address to start the REST server on. const HTRACE_WEB_ADDRESS = "web.address" // The default port for the Htrace web address. const HTRACE_WEB_ADDRESS_DEFAULT_PORT = 9095 // The directories to put the data store into. Separated by PATH_LIST_SEP. const HTRACE_DATA_STORE_DIRECTORIES = "data.store.directories" // Boolean key which indicates whether we should clear data on startup. const HTRACE_DATA_STORE_CLEAR = "data.store.clear" // How many writes to buffer before applying backpressure to span senders. const HTRACE_DATA_STORE_SPAN_BUFFER_SIZE = "data.store.span.buffer.size" // Default values for HTrace configuration keys. var DEFAULTS = map[string]string{ HTRACE_WEB_ADDRESS: fmt.Sprintf("0.0.0.0:%d", HTRACE_WEB_ADDRESS_DEFAULT_PORT), HTRACE_DATA_STORE_DIRECTORIES: PATH_SEP + "tmp" + PATH_SEP + "htrace1" + PATH_LIST_SEP + PATH_SEP + "tmp" + PATH_SEP + "htrace2", HTRACE_DATA_STORE_CLEAR: "false", HTRACE_DATA_STORE_SPAN_BUFFER_SIZE: "100", } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/conf/config_test.go000066400000000000000000000057421245601110500301650ustar00rootroot00000000000000/* * 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 conf import ( "strings" "testing" ) // Test that parsing command-line arguments of the form -Dfoo=bar works. func TestParseArgV(t *testing.T) { t.Parallel() argv := []string{"-Dfoo=bar", "-Dbaz=123", "-DsillyMode"} bld := &Builder{Argv: argv} cnf, err := bld.Build() if err != nil { t.Fatal() } if "bar" != cnf.Get("foo") { t.Fatal() } if 123 != cnf.GetInt("baz") { t.Fatal() } if !cnf.GetBool("sillyMode") { t.Fatal() } if cnf.GetBool("otherSillyMode") { t.Fatal() } } // Test that default values work. // Defaults are used only when the configuration option is not present or can't be parsed. func TestDefaults(t *testing.T) { t.Parallel() argv := []string{"-Dfoo=bar", "-Dbaz=invalidNumber"} defaults := map[string]string{ "foo": "notbar", "baz": "456", "foo2": "4611686018427387904", } bld := &Builder{Argv: argv, Defaults: defaults} cnf, err := bld.Build() if err != nil { t.Fatal() } if "bar" != cnf.Get("foo") { t.Fatal() } if 456 != cnf.GetInt("baz") { t.Fatal() } if 4611686018427387904 != cnf.GetInt64("foo2") { t.Fatal() } } // Test that we can parse our XML configuration file. func TestXmlConfigurationFile(t *testing.T) { t.Parallel() xml := ` foo.bar 123 foo.baz xmlValue ` xmlReader := strings.NewReader(xml) argv := []string{"-Dfoo.bar=456"} defaults := map[string]string{ "foo.bar": "789", "cmdline.opt": "4611686018427387904", } bld := &Builder{Argv: argv, Defaults: defaults, Reader: xmlReader} cnf, err := bld.Build() if err != nil { t.Fatal() } // The command-line argument takes precedence over the XML and the defaults. if 456 != cnf.GetInt("foo.bar") { t.Fatal() } if "xmlValue" != cnf.Get("foo.baz") { t.Fatalf("foo.baz = %s", cnf.Get("foo.baz")) } if "" != cnf.Get("commented.out") { t.Fatal() } if 4611686018427387904 != cnf.GetInt64("cmdline.opt") { t.Fatal() } } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/conf/xml.go000066400000000000000000000032321245601110500264510ustar00rootroot00000000000000/* * 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 conf import ( "encoding/xml" "io" "log" ) type configuration struct { Properties []propertyXml `xml:"property"` } type propertyXml struct { Name string `xml:"name"` Value string `xml:"value"` } // Parse an XML configuration file. func parseXml(reader io.Reader, m map[string]string) error { dec := xml.NewDecoder(reader) configurationXml := configuration{} err := dec.Decode(&configurationXml) if err != nil { return err } props := configurationXml.Properties for p := range props { key := props[p].Name value := props[p].Value if key == "" { log.Println("Warning: ignoring element with missing or empty .") continue } if value == "" { log.Println("Warning: ignoring element with key " + key + " with missing or empty .") continue } //log.Printf("setting %s to %s\n", key, value) m[key] = value } return nil } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htrace/000077500000000000000000000000001245601110500256435ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htrace/cmd.go000066400000000000000000000121441245601110500267370ustar00rootroot00000000000000/* * 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 ( "encoding/json" "errors" "fmt" "github.com/alecthomas/kingpin" "io/ioutil" "net/http" "org/apache/htrace/common" "org/apache/htrace/conf" "os" ) var RELEASE_VERSION string var GIT_VERSION string func main() { // Load htraced configuration cnf := conf.LoadApplicationConfig() // Parse argv app := kingpin.New("htrace", "The HTrace tracing utility.") addr := app.Flag("addr", "Server address."). Default(cnf.Get(conf.HTRACE_WEB_ADDRESS)).TCP() 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.Flag("id", "Span ID to find, as a signed decimal 64-bit "+ "number").Required().Int64() findChildren := app.Command("findChildren", "Print out the span IDs that are children of a given span ID.") parentSpanId := findChildren.Flag("id", "Span ID to print children for, as a signed decimal 64-bit "+ "number").Required().Int64() childLim := findChildren.Flag("lim", "Maximum number of child IDs to print.").Default("20").Int() // Handle operation switch kingpin.MustParse(app.Parse(os.Args[1:])) { case version.FullCommand(): os.Exit(printVersion()) case serverInfo.FullCommand(): os.Exit(printServerInfo((*addr).String())) case findSpan.FullCommand(): os.Exit(doFindSpan((*addr).String(), *findSpanId)) case findChildren.FullCommand(): os.Exit(doFindChildren((*addr).String(), *parentSpanId, *childLim)) } 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 0 } // Print information retrieved from an htraced server via /serverInfo func printServerInfo(restAddr string) int { buf, err := makeRestRequest(restAddr, "serverInfo") if err != nil { fmt.Printf("%s\n", err.Error()) return 1 } var info common.ServerInfo err = json.Unmarshal(buf, &info) if err != nil { fmt.Printf("Error: error unmarshalling response body %s: %s\n", string(buf), err.Error()) return 1 } fmt.Printf("HTraced server version %s (%s)\n", info.ReleaseVersion, info.GitVersion) return 0 } // Print information about a trace span. func doFindSpan(restAddr string, sid int64) int { buf, err := makeRestRequest(restAddr, fmt.Sprintf("findSid?sid=%016x", sid)) if err != nil { fmt.Printf("%s\n", err.Error()) return 1 } var span common.Span err = json.Unmarshal(buf, &span) if err != nil { fmt.Printf("Error: error unmarshalling response body %s: %s\n", string(buf), err.Error()) return 1 } pbuf, err := json.MarshalIndent(span, "", " ") if err != nil { fmt.Println("Error: error pretty-printing span to JSON: %s", err.Error()) return 1 } fmt.Printf("%s\n", string(pbuf)) return 0 } // Find information about the children of a span. func doFindChildren(restAddr string, sid int64, lim int) int { buf, err := makeRestRequest(restAddr, fmt.Sprintf("findChildren?sid=%016x&lim=%d", sid, lim)) if err != nil { fmt.Printf("%s\n", err.Error()) return 1 } var spanIds []int64 err = json.Unmarshal(buf, &spanIds) if err != nil { fmt.Printf("Error: error unmarshalling response body %s: %s\n", string(buf), err.Error()) return 1 } 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 } // Print information retrieved from an htraced server via /serverInfo func makeRestRequest(restAddr string, reqName string) ([]byte, error) { url := fmt.Sprintf("http://%s/%s", restAddr, reqName) req, err := http.NewRequest("GET", url, nil) client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, errors.New(fmt.Sprintf("Error: error making http request to %s: %s\n", url, err.Error())) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, errors.New(fmt.Sprintf("Error: got bad response status from %s: %s\n", url, resp.Status)) } var body []byte body, err = ioutil.ReadAll(resp.Body) if err != nil { return nil, errors.New(fmt.Sprintf("Error: error reading response body: %s\n", err.Error())) } return body, nil } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htraced/000077500000000000000000000000001245601110500260075ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htraced/datastore.go000066400000000000000000000266231245601110500303350ustar00rootroot00000000000000/* * 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 ( "bytes" "encoding/gob" "github.com/jmhodges/levigo" "log" "org/apache/htrace/common" "org/apache/htrace/conf" "os" "strings" "sync/atomic" "syscall" ) // // The data store code for HTraced. // // This code stores the trace spans. We use levelDB here so that we don't have to store everything // in memory at all times. The data is sharded across multiple levelDB databases in multiple // directories. Normally, these multiple directories will be on multiple disk drives. // // The main emphasis in the HTraceD data store is on quickly and efficiently storing trace span data // coming from many daemons. Durability is not as big a concern as in some data stores, since // losing a little bit of trace data if htraced goes down is not critical. We use the "gob" package // for serialization. We assume that there will be many more writes than reads. // // TODO: implement redundancy (storing data on more than 1 drive) // TODO: implement re-loading old span data // // Schema // m -> dataStoreMetadata // s[8-byte-big-endian-sid] -> SpanData // p[8-byte-big-endian-parent-sid][8-byte-big-endian-child-sid] -> {} // t[8-byte-big-endian-time][8-byte-big-endian-child-sid] -> {} // const DATA_STORE_VERSION = 1 var EMPTY_BYTE_BUF []byte = []byte{} type Statistics struct { NumSpansWritten uint64 } func (stats *Statistics) IncrementWrittenSpans() { atomic.AddUint64(&stats.NumSpansWritten, 1) } // Make a copy of the statistics structure, using atomic operations. func (stats *Statistics) Copy() *Statistics { return &Statistics{ NumSpansWritten: atomic.LoadUint64(&stats.NumSpansWritten), } } // Translate a span id into a leveldb key. func makeKey(tag byte, sid int64) []byte { id := uint64(sid) return []byte{ tag, byte(0xff & (id >> 56)), byte(0xff & (id >> 48)), byte(0xff & (id >> 40)), byte(0xff & (id >> 32)), byte(0xff & (id >> 24)), byte(0xff & (id >> 16)), byte(0xff & (id >> 8)), byte(0xff & (id >> 0)), } } func keyToInt(key []byte) int64 { var id uint64 id = (uint64(key[0]) << 56) | (uint64(key[1]) << 48) | (uint64(key[2]) << 40) | (uint64(key[3]) << 32) | (uint64(key[4]) << 24) | (uint64(key[5]) << 16) | (uint64(key[6]) << 8) | (uint64(key[7]) << 0) return int64(id) } func makeSecondaryKey(tag byte, first int64, second int64) []byte { fir := uint64(first) sec := uint64(second) return []byte{ tag, byte(0xff & (fir >> 56)), byte(0xff & (fir >> 48)), byte(0xff & (fir >> 40)), byte(0xff & (fir >> 32)), byte(0xff & (fir >> 24)), byte(0xff & (fir >> 16)), byte(0xff & (fir >> 8)), byte(0xff & (fir >> 0)), byte(0xff & (sec >> 56)), byte(0xff & (sec >> 48)), byte(0xff & (sec >> 40)), byte(0xff & (sec >> 32)), byte(0xff & (sec >> 24)), byte(0xff & (sec >> 16)), byte(0xff & (sec >> 8)), byte(0xff & (sec >> 0)), } } // A single directory containing a levelDB instance. type shard struct { // The data store that this shard is part of store *dataStore // The LevelDB instance. ldb *levigo.DB // The path to the leveldb directory this shard is managing. path string // Incoming requests to write Spans. incoming chan *common.Span // The channel we will send a bool to when we exit. exited chan bool } // Metadata about the DataStore. type dataStoreMetadata struct { // The DataStore version. Version int32 } // Write the metadata key to a shard. func (shd *shard) WriteMetadata(meta *dataStoreMetadata) error { w := new(bytes.Buffer) encoder := gob.NewEncoder(w) err := encoder.Encode(meta) if err != nil { return err } return shd.ldb.Put(shd.store.writeOpts, []byte("m"), w.Bytes()) } // Process incoming spans for a shard. func (shd *shard) processIncoming() { for { span := <-shd.incoming if span == nil { log.Printf("Shard processor for %s exiting.", shd.path) shd.exited <- true return } err := shd.writeSpan(span) if err != nil { log.Fatal("Shard processor for %s got fatal error %s.", shd.path, err.Error()) } //log.Printf("Shard processor for %s wrote span %s.", shd.path, span.ToJson()) } } func (shd *shard) writeSpan(span *common.Span) error { batch := levigo.NewWriteBatch() defer batch.Close() // Add SpanData to batch. spanDataBuf := new(bytes.Buffer) spanDataEnc := gob.NewEncoder(spanDataBuf) err := spanDataEnc.Encode(span.SpanData) if err != nil { return err } batch.Put(makeKey('s', span.Id.Val()), spanDataBuf.Bytes()) // Add this to the parent index. for parentIdx := range span.Parents { batch.Put(makeSecondaryKey('p', span.Parents[parentIdx].Val(), span.Id.Val()), EMPTY_BYTE_BUF) } // Add this to the timeline index. batch.Put(makeSecondaryKey('t', span.Begin, span.Id.Val()), EMPTY_BYTE_BUF) err = shd.ldb.Write(shd.store.writeOpts, batch) if err != nil { return err } shd.store.stats.IncrementWrittenSpans() if shd.store.WrittenSpans != nil { shd.store.WrittenSpans <- span } return nil } func (shd *shard) FindChildren(sid int64, childIds []int64, lim int32) ([]int64, int32, error) { searchKey := makeKey('p', sid) iter := shd.ldb.NewIterator(shd.store.readOpts) defer iter.Close() iter.Seek(searchKey) for { if !iter.Valid() { break } if lim == 0 { break } key := iter.Key() if !bytes.HasPrefix(key, searchKey) { break } id := keyToInt(key[9:]) childIds = append(childIds, id) lim-- iter.Next() } return childIds, lim, nil } // Close a shard. func (shd *shard) Close() { shd.incoming <- nil log.Printf("Waiting for %s to exit...", shd.path) if shd.exited != nil { <-shd.exited } shd.ldb.Close() log.Printf("Closed %s...", shd.path) } // The Data Store. type dataStore struct { // The shards which manage our LevelDB instances. shards []*shard // I/O statistics for all shards. stats Statistics // The read options to use for LevelDB. readOpts *levigo.ReadOptions // The write options to use for LevelDB. writeOpts *levigo.WriteOptions // If non-null, a channel we will send spans to once we finish writing them. This is only used // for testing. WrittenSpans chan *common.Span } 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) // If we return an error, close the store. var err error store := &dataStore{shards: []*shard{}, WrittenSpans: writtenSpans} 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" err := os.MkdirAll(path, 0777) if err != nil { e, ok := err.(*os.PathError) if !ok || e.Err != syscall.EEXIST { return nil, err } if !clearStored { // TODO: implement re-opening saved data log.Println("Error: path " + path + "already exists.") return nil, err } else { err = os.RemoveAll(path) if err != nil { log.Println("Failed to create " + path + ": " + err.Error()) return nil, err } log.Println("Cleared " + path) } } var shd *shard shd, err = CreateShard(store, cnf, path) if err != nil { log.Printf("Error creating shard %s: %s", path, err.Error()) return nil, err } store.shards = append(store.shards, shd) } meta := &dataStoreMetadata{Version: DATA_STORE_VERSION} for idx := range store.shards { shd := store.shards[idx] err := shd.WriteMetadata(meta) if err != nil { log.Println("Failed to write metadata to " + store.shards[idx].path + ": " + err.Error()) return nil, err } shd.exited = make(chan bool, 1) go shd.processIncoming() } return store, nil } func CreateShard(store *dataStore, cnf *conf.Config, path string) (*shard, error) { var shd *shard //filter := levigo.NewBloomFilter(10) //defer filter.Close() openOpts := levigo.NewOptions() defer openOpts.Close() openOpts.SetCreateIfMissing(true) //openOpts.SetFilterPolicy(filter) ldb, err := levigo.Open(path, openOpts) if err != nil { log.Println("LevelDB failed to open " + path + ": " + err.Error()) return nil, err } defer func() { if shd == nil { ldb.Close() } }() spanBufferSize := cnf.GetInt(conf.HTRACE_DATA_STORE_SPAN_BUFFER_SIZE) shd = &shard{store: store, ldb: ldb, path: path, incoming: make(chan *common.Span, spanBufferSize)} log.Println("LevelDB opened " + path) return shd, nil } func (store *dataStore) GetStatistics() *Statistics { return store.stats.Copy() } // Close the DataStore. func (store *dataStore) Close() { for idx := range store.shards { store.shards[idx].Close() } if store.readOpts != nil { store.readOpts.Close() } if store.writeOpts != nil { store.writeOpts.Close() } } // Get the index of the shard which stores the given spanId. func (store *dataStore) getShardIndex(spanId int64) int { return int(uint64(spanId) % uint64(len(store.shards))) } func (store *dataStore) WriteSpan(span *common.Span) { store.shards[store.getShardIndex(span.Id.Val())].incoming <- span } func (store *dataStore) FindSpan(sid int64) *common.Span { return store.shards[store.getShardIndex(sid)].FindSpan(sid) } func (shd *shard) FindSpan(sid int64) *common.Span { buf, err := shd.ldb.Get(shd.store.readOpts, makeKey('s', sid)) if err != nil { if strings.Index(err.Error(), "NotFound:") != -1 { return nil } log.Printf("Shard(%s): FindSpan(%d) error: %s\n", shd.path, sid, err.Error()) return nil } r := bytes.NewBuffer(buf) decoder := gob.NewDecoder(r) data := common.SpanData{} err = decoder.Decode(&data) if err != nil { log.Printf("Shard(%s): FindSpan(%d) decode error: %s\n", shd.path, sid, err.Error()) return nil } // Gob encoding translates empty slices to nil. Reverse this so that we're always dealing with // non-nil slices. if data.Parents == nil { data.Parents = []common.SpanId{} } return &common.Span{Id: common.SpanId(sid), SpanData: data} } // Find the children of a given span id. func (store *dataStore) FindChildren(sid int64, lim int32) []int64 { childIds := make([]int64, 0) var err error startIdx := store.getShardIndex(sid) idx := startIdx numShards := len(store.shards) for { if lim == 0 { break } shd := store.shards[idx] childIds, lim, err = shd.FindChildren(sid, childIds, lim) if err != nil { log.Printf("Shard(%s): FindChildren(%d) error: %s\n", shd.path, sid, err.Error()) } idx++ if idx >= numShards { idx = 0 } if idx == startIdx { break } } return childIds } //func (store *dataStore) FindByTimeRange(startTime int64, endTime int64, lim int32) []int64 { //} incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htraced/datastore_test.go000066400000000000000000000074261245601110500313740ustar00rootroot00000000000000/* * 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 ( "math/rand" "org/apache/htrace/common" "org/apache/htrace/test" "sort" "testing" ) // Test creating and tearing down a datastore. func TestCreateDatastore(t *testing.T) { htraceBld := &MiniHTracedBuilder{Name: "TestCreateDatastore", NumDataDirs: 3} ht, err := htraceBld.Build() if err != nil { t.Fatalf("failed to create datastore: %s", err.Error()) } defer ht.Close() } var SIMPLE_TEST_SPANS []common.Span = []common.Span{ common.Span{Id: 1, SpanData: common.SpanData{ Begin: 123, End: 456, Description: "getFileDescriptors", TraceId: 999, Parents: []common.SpanId{}, ProcessId: "firstd", }}, common.Span{Id: 2, SpanData: common.SpanData{ Begin: 125, End: 200, Description: "openFd", TraceId: 999, Parents: []common.SpanId{1}, ProcessId: "secondd", }}, common.Span{Id: 3, SpanData: common.SpanData{ Begin: 200, End: 456, Description: "passFd", TraceId: 999, Parents: []common.SpanId{1}, ProcessId: "thirdd", }}, } func createSpans(spans []common.Span, store *dataStore) { for idx := range spans { store.WriteSpan(&spans[idx]) } // Wait the spans to be created for i := 0; i < 3; i++ { <-store.WrittenSpans } } // Test creating a datastore and adding some spans. func TestDatastoreWriteAndRead(t *testing.T) { t.Parallel() htraceBld := &MiniHTracedBuilder{Name: "TestDatastoreWriteAndRead", WrittenSpans: make(chan *common.Span, 100)} ht, err := htraceBld.Build() if err != nil { panic(err) } defer ht.Close() createSpans(SIMPLE_TEST_SPANS, ht.Store) if ht.Store.GetStatistics().NumSpansWritten < uint64(len(SIMPLE_TEST_SPANS)) { t.Fatal() } span := ht.Store.FindSpan(1) if span == nil { t.Fatal() } if span.Id != 1 { t.Fatal() } common.ExpectSpansEqual(t, &SIMPLE_TEST_SPANS[0], span) children := ht.Store.FindChildren(1, 1) if len(children) != 1 { t.Fatalf("expected 1 child, but got %d\n", len(children)) } children = ht.Store.FindChildren(1, 2) if len(children) != 2 { t.Fatalf("expected 2 children, but got %d\n", len(children)) } sort.Sort(common.Int64Slice(children)) if children[0] != 2 { t.Fatal() } if children[1] != 3 { t.Fatal() } } func BenchmarkDatastoreWrites(b *testing.B) { htraceBld := &MiniHTracedBuilder{Name: "BenchmarkDatastoreWrites", WrittenSpans: make(chan *common.Span, b.N)} ht, err := htraceBld.Build() if err != nil { panic(err) } defer ht.Close() rnd := rand.New(rand.NewSource(1)) allSpans := make([]*common.Span, b.N) // Write many random spans. for n := 0; n < b.N; n++ { span := test.NewRandomSpan(rnd, allSpans[0:n]) ht.Store.WriteSpan(span) allSpans[n] = span } // Wait for all the spans to be written. for n := 0; n < b.N; n++ { <-ht.Store.WrittenSpans } spansWritten := ht.Store.GetStatistics().NumSpansWritten if spansWritten < uint64(b.N) { b.Fatal("incorrect statistics: expected %d spans to be written, but only got %d", b.N, spansWritten) } } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htraced/htraced.go000066400000000000000000000021421245601110500277470ustar00rootroot00000000000000/* * 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 ( "log" "org/apache/htrace/conf" ) var RELEASE_VERSION string var GIT_VERSION string func main() { cnf := conf.LoadApplicationConfig() store, err := CreateDataStore(cnf, nil) if err != nil { log.Fatalf("Error creating datastore: %s\n", err.Error()) } startRestServer(cnf, store) } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htraced/mini_htraced.go000066400000000000000000000060111245601110500307620ustar00rootroot00000000000000/* * 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 ( "fmt" "io/ioutil" "org/apache/htrace/common" "org/apache/htrace/conf" "os" "strings" ) // // MiniHTraceD is used in unit tests to set up a daemon with certain settings. // It takes care of things like creating and cleaning up temporary directories. // // The default number of managed data directories to use. const DEFAULT_NUM_DATA_DIRS = 2 // Builds a MiniHTraced object. type MiniHTracedBuilder struct { // The name of the MiniHTraced to build. This shows up in the test directory name and some // other places. Name string // The configuration values to use for the MiniHTraced. // If ths is nil, we use the default configuration for everything. Cnf map[string]string // The number of managed data directories to create. // If this is 0, it defaults to DEFAULT_NUM_DATA_DIRS. NumDataDirs int // If non-null, the WrittenSpans channel to use when creating the DataStore. WrittenSpans chan *common.Span } type MiniHTraced struct { Name string Cnf *conf.Config DataDirs []string Store *dataStore } func (bld *MiniHTracedBuilder) Build() (*MiniHTraced, error) { var err error var store *dataStore if bld.Name == "" { bld.Name = "HTraceTest" } if bld.Cnf == nil { bld.Cnf = make(map[string]string) } if bld.NumDataDirs == 0 { bld.NumDataDirs = DEFAULT_NUM_DATA_DIRS } dataDirs := make([]string, bld.NumDataDirs) defer func() { if err != nil { if store != nil { store.Close() } for idx := range dataDirs { if dataDirs[idx] != "" { os.RemoveAll(dataDirs[idx]) } } } }() for idx := range dataDirs { 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(dataDirs, conf.PATH_LIST_SEP) cnfBld := conf.Builder{Values: bld.Cnf, Defaults: conf.DEFAULTS} cnf, err := cnfBld.Build() if err != nil { return nil, err } store, err = CreateDataStore(cnf, bld.WrittenSpans) if err != nil { return nil, err } return &MiniHTraced{ Cnf: cnf, DataDirs: dataDirs, Store: store, }, nil } func (ht *MiniHTraced) Close() { ht.Store.Close() for idx := range ht.DataDirs { os.RemoveAll(ht.DataDirs[idx]) } } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/htraced/rest.go000066400000000000000000000103031245601110500273100ustar00rootroot00000000000000/* * 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 ( "encoding/json" "log" "net/http" "org/apache/htrace/common" "org/apache/htrace/conf" "org/apache/htrace/resource" "strconv" "strings" ) type serverInfoHandler struct { } func (handler *serverInfoHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { version := common.ServerInfo{ReleaseVersion: RELEASE_VERSION, GitVersion: GIT_VERSION} buf, err := json.Marshal(&version) if err != nil { log.Printf("error marshalling ServerInfo: %s\n", err.Error()) w.WriteHeader(http.StatusInternalServerError) return } w.Write(buf) } type dataStoreHandler struct { store *dataStore } func (hand *dataStoreHandler) getReqField64(fieldName string, w http.ResponseWriter, req *http.Request) (int64, bool) { str := req.FormValue(fieldName) if str == "" { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("No " + fieldName + " specified.")) return -1, false } val, err := strconv.ParseUint(str, 16, 64) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Error parsing " + fieldName + ": " + err.Error())) return -1, false } return int64(val), true } func (hand *dataStoreHandler) getReqField32(fieldName string, w http.ResponseWriter, req *http.Request) (int32, bool) { str := req.FormValue(fieldName) if str == "" { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("No " + fieldName + " specified.")) return -1, false } val, err := strconv.ParseUint(str, 16, 32) if err != nil { w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Error parsing " + fieldName + ": " + err.Error())) return -1, false } return int32(val), true } type findSidHandler struct { dataStoreHandler } func (hand *findSidHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { req.ParseForm() sid, ok := hand.getReqField64("sid", w, req) if !ok { return } span := hand.store.FindSpan(sid) if span == nil { w.WriteHeader(http.StatusNoContent) return } w.Write(span.ToJson()) } type findChildrenHandler struct { dataStoreHandler } func (hand *findChildrenHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { req.ParseForm() sid, ok := hand.getReqField64("sid", w, req) if !ok { return } var lim int32 lim, ok = hand.getReqField32("lim", w, req) if !ok { return } children := hand.store.FindChildren(sid, lim) if len(children) == 0 { w.WriteHeader(http.StatusNoContent) return } jbytes, err := json.Marshal(children) if err != nil { panic(err) } w.Write(jbytes) } type defaultServeHandler struct { } func (hand *defaultServeHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { ident := strings.TrimLeft(req.URL.Path, "/") ident = strings.Replace(ident, "/", "__", -1) rsc := resource.Catalog[ident] if rsc == "" { log.Printf("failed to find entry for %s\n", ident) w.WriteHeader(http.StatusNotFound) return } w.Write([]byte(rsc)) } func startRestServer(cnf *conf.Config, store *dataStore) { mux := http.NewServeMux() serverInfoH := &serverInfoHandler{} mux.Handle("/serverInfo", serverInfoH) findSidH := &findSidHandler{dataStoreHandler: dataStoreHandler{store: store}} mux.Handle("/findSid", findSidH) findChildrenH := &findChildrenHandler{dataStoreHandler: dataStoreHandler{store: store}} mux.Handle("/findChildren", findChildrenH) defaultServeH := &defaultServeHandler{} mux.Handle("/", defaultServeH) http.ListenAndServe(cnf.Get(conf.HTRACE_WEB_ADDRESS), mux) log.Println("Started REST server...") } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/resource/000077500000000000000000000000001245601110500262245ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/resource/catalog.go000066400000000000000000000020511245601110500301630ustar00rootroot00000000000000/* * 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 resource // Map containing all resources. var Catalog map[string]string = make(map[string]string) // Function called by generated code to add a resource to the catalog. func addResource(key, val string) string { Catalog[key] = val return key } incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/test/000077500000000000000000000000001245601110500253545ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/go/src/org/apache/htrace/test/random.go000066400000000000000000000035151245601110500271670ustar00rootroot00000000000000/* * 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 test import ( "fmt" "math/rand" "org/apache/htrace/common" ) func NonZeroRand64(rnd *rand.Rand) int64 { for { r := rnd.Int63() if r == 0 { continue } if rnd.Intn(1) != 0 { return -r } return r } } func NonZeroRand32(rnd *rand.Rand) int32 { for { r := rnd.Int31() if r == 0 { continue } if rnd.Intn(1) != 0 { return -r } return r } } // Create a random span. func NewRandomSpan(rnd *rand.Rand, potentialParents []*common.Span) *common.Span { parents := []common.SpanId{} if potentialParents != nil { parentIdx := rnd.Intn(len(potentialParents) + 1) if parentIdx < len(potentialParents) { parents = []common.SpanId{potentialParents[parentIdx].Id} } } return &common.Span{Id: common.SpanId(NonZeroRand64(rnd)), SpanData: common.SpanData{ Begin: NonZeroRand64(rnd), End: NonZeroRand64(rnd), Description: "getFileDescriptors", TraceId: common.SpanId(NonZeroRand64(rnd)), Parents: parents, ProcessId: fmt.Sprintf("process%d", NonZeroRand32(rnd)), }} } incubator-htrace-3.1.0/htrace-core/src/main/000077500000000000000000000000001245601110500206475ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/000077500000000000000000000000001245601110500215705ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/org/000077500000000000000000000000001245601110500223575ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/000077500000000000000000000000001245601110500236005ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/000077500000000000000000000000001245601110500250465ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/HTraceConfiguration.java000066400000000000000000000064621245601110500316170ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.HashMap; import java.util.Map; /** * Wrapper which integrating applications should implement in order * to provide tracing configuration. */ public abstract class HTraceConfiguration { private static final Log LOG = LogFactory.getLog(HTraceConfiguration.class); private static final Map EMPTY_MAP = new HashMap(1); /** * An empty HTrace configuration. */ public static final HTraceConfiguration EMPTY = fromMap(EMPTY_MAP); /** * Create an HTrace configuration from a map. * * @param conf The map to create the configuration from. * @return The new configuration. */ public static HTraceConfiguration fromMap(Map conf) { return new MapConf(conf); } static HTraceConfiguration fromKeyValuePairs(String... pairs) { if ((pairs.length % 2) != 0) { throw new RuntimeException("You must specify an equal number of keys " + "and values."); } Map conf = new HashMap(); for (int i = 0; i < pairs.length; i+=2) { conf.put(pairs[i], pairs[i + 1]); } return new MapConf(conf); } public abstract String get(String key); public abstract String get(String key, String defaultValue); public boolean getBoolean(String key, boolean defaultValue) { String value = get(key, String.valueOf(defaultValue)).trim().toLowerCase(); if ("true".equals(value)) { return true; } else if ("false".equals(value)) { return false; } LOG.warn("Expected boolean for key [" + key + "] instead got [" + value + "]."); return defaultValue; } public int getInt(String key, int defaultVal) { String val = get(key); if (val == null || val.trim().isEmpty()) { return defaultVal; } try { return Integer.parseInt(val); } catch (NumberFormatException nfe) { throw new IllegalArgumentException("Bad value for '" + key + "': should be int"); } } private static class MapConf extends HTraceConfiguration { private final Map conf; public MapConf(Map conf) { this.conf = new HashMap(conf); } @Override public String get(String key) { return conf.get(key); } @Override public String get(String key, String defaultValue) { String value = get(key); return value == null ? defaultValue : value; } } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/NullScope.java000066400000000000000000000021621245601110500276160ustar00rootroot00000000000000/* * 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 org.apache.htrace; /** * Singleton instance representing an empty {@link TraceScope}. */ public final class NullScope extends TraceScope { public static final TraceScope INSTANCE = new NullScope(); private NullScope() { super(null, null); } @Override public String toString() { return "NullScope"; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/Sampler.java000066400000000000000000000040721245601110500273170ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.htrace.impl.AlwaysSampler; import org.apache.htrace.impl.NeverSampler; /** * Extremely simple callback to determine the frequency that an action should be * performed. *

* 'T' is the object type you require to create a more advanced sampling * function. For example if there is some RPC information in a 'Call' object, * you might implement Sampler. Then when the RPC is received you can call * one of the Trace.java functions that takes the extra 'info' parameter, which * will be passed into the next function you implemented. *

* For the example above, the next(T info) function may look like this *

*

 * public boolean next(T info) {
 *   if (info == null) {
 *     return false;
 *   } else if (info.getName().equals("get")) {
 *     return Math.random() > 0.5;
 *   } else if (info.getName().equals("put")) {
 *     return Math.random() > 0.25;
 *   } else {
 *     return false;
 *   }
 * }
 * 
 * 
* This would trace 50% of all gets, 75% of all puts and would not trace any other requests. */ public interface Sampler { public static final Sampler ALWAYS = AlwaysSampler.INSTANCE; public static final Sampler NEVER = NeverSampler.INSTANCE; public boolean next(T info); } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/SamplerBuilder.java000066400000000000000000000062401245601110500306250ustar00rootroot00000000000000/* * 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 org.apache.htrace; import java.lang.reflect.Constructor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.htrace.impl.AlwaysSampler; import org.apache.htrace.impl.NeverSampler; /** * A {@link Sampler} builder. It reads a {@link Sampler} class name from the provided * configuration using the {@link #SAMPLER_CONF_KEY} key. Unqualified class names * are interpreted as members of the {@code org.apache.htrace.impl} package. The {@link #build()} * method constructs an instance of that class, initialized with the same configuration. */ public class SamplerBuilder { // TODO: should follow the same API as SpanReceiverBuilder public final static String SAMPLER_CONF_KEY = "sampler"; private final static String DEFAULT_PACKAGE = "org.apache.htrace.impl"; private final static ClassLoader classLoader = SamplerBuilder.class.getClassLoader(); private final HTraceConfiguration conf; private static final Log LOG = LogFactory.getLog(SamplerBuilder.class); public SamplerBuilder(HTraceConfiguration conf) { this.conf = conf; } public Sampler build() { String str = conf.get(SAMPLER_CONF_KEY); if (str.isEmpty()) { return NeverSampler.INSTANCE; } if (!str.contains(".")) { str = DEFAULT_PACKAGE + "." + str; } Class cls = null; try { cls = classLoader.loadClass(str); } catch (ClassNotFoundException e) { LOG.error("SamplerBuilder cannot find sampler class " + str + ": falling back on NeverSampler."); return NeverSampler.INSTANCE; } Constructor ctor = null; try { ctor = cls.getConstructor(HTraceConfiguration.class); } catch (NoSuchMethodException e) { LOG.error("SamplerBuilder cannot find a constructor for class " + str + "which takes an HTraceConfiguration. Falling back on " + "NeverSampler."); return NeverSampler.INSTANCE; } try { return ctor.newInstance(conf); } catch (ReflectiveOperationException e) { LOG.error("SamplerBuilder reflection error when constructing " + str + ". Falling back on NeverSampler.", e); return NeverSampler.INSTANCE; } catch (Throwable e) { LOG.error("SamplerBuilder constructor error when constructing " + str + ". Falling back on NeverSampler.", e); return NeverSampler.INSTANCE; } } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/Span.java000066400000000000000000000115201245601110500266110ustar00rootroot00000000000000/* * 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 org.apache.htrace; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.io.IOException; import java.util.List; import java.util.Map; /** * Base interface for gathering and reporting statistics about a block of * execution. *

* Spans form a tree structure with the parent relationship. The first span in a * trace has no parent span. */ @JsonSerialize(using = Span.SpanSerializer.class) public interface Span { public static final long ROOT_SPAN_ID = 0x74ace; /** * The block has completed, stop the clock */ void stop(); /** * Get the start time, in milliseconds */ long getStartTimeMillis(); /** * Get the stop time, in milliseconds */ long getStopTimeMillis(); /** * Return the total amount of time elapsed since start was called, if running, * or difference between stop and start */ long getAccumulatedMillis(); /** * Has the span been started and not yet stopped? */ boolean isRunning(); /** * Return a textual description of this span */ String getDescription(); /** * A pseudo-unique (random) number assigned to this span instance */ long getSpanId(); /** * A pseudo-unique (random) number assigned to the trace associated with this * span */ long getTraceId(); /** * Create a child span of this span with the given description */ Span child(String description); @Override String toString(); /** * Return the pseudo-unique (random) number of the first parent span, returns * ROOT_SPAN_ID if there are no parents. */ long getParentId(); /** * Add a data annotation associated with this span */ void addKVAnnotation(byte[] key, byte[] value); /** * Add a timeline annotation associated with this span */ void addTimelineAnnotation(String msg); /** * Get data associated with this span (read only) */ Map getKVAnnotations(); /** * Get any timeline annotations (read only) */ List getTimelineAnnotations(); /** * Return a unique id for the node or process from which this Span originated. * IP address is a reasonable choice. * * @return */ String getProcessId(); /** * Serialize to Json */ String toJson(); public static class SpanSerializer extends JsonSerializer { @Override public void serialize(Span span, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeStartObject(); jgen.writeStringField("i", String.format("%016x", span.getTraceId())); jgen.writeStringField("s", String.format("%016x", span.getSpanId())); jgen.writeNumberField("b", span.getStartTimeMillis()); jgen.writeNumberField("e", span.getStopTimeMillis()); jgen.writeStringField("d", span.getDescription()); jgen.writeStringField("r", span.getProcessId()); jgen.writeArrayFieldStart("p"); if (span.getParentId() != ROOT_SPAN_ID) { jgen.writeString(String.format("%016x", span.getParentId())); } jgen.writeEndArray(); Map traceInfoMap = span.getKVAnnotations(); if (!traceInfoMap.isEmpty()) { jgen.writeObjectFieldStart("n"); for (Map.Entry e : traceInfoMap.entrySet()) { jgen.writeStringField(new String(e.getKey(), "UTF-8"), new String(e.getValue(), "UTF-8")); } jgen.writeEndObject(); } List timelineAnnotations = span.getTimelineAnnotations(); if (!timelineAnnotations.isEmpty()) { jgen.writeArrayFieldStart("t"); for (TimelineAnnotation tl : timelineAnnotations) { jgen.writeStartObject(); jgen.writeNumberField("t", tl.getTime()); jgen.writeStringField("m", tl.getMessage()); jgen.writeEndObject(); } jgen.writeEndArray(); } jgen.writeEndObject(); } } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/SpanReceiver.java000066400000000000000000000027561245601110500303110ustar00rootroot00000000000000/* * 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 org.apache.htrace; import java.io.Closeable; /** * The collector within a process that is the destination of Spans when a trace is running. * {@code SpanReceiver} implementations are expected to provide a constructor with the signature *

*

 * public SpanReceiverImpl(HTraceConfiguration)
 * 
* The helper class {@link org.apache.htrace.SpanReceiverBuilder} provides convenient factory * methods for creating {@code SpanReceiver} instances from configuration. * @see org.apache.htrace.SpanReceiverBuilder */ public interface SpanReceiver extends Closeable { /** * Called when a Span is stopped and can now be stored. */ public void receiveSpan(Span span); } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/SpanReceiverBuilder.java000066400000000000000000000102611245601110500316060ustar00rootroot00000000000000/* * 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 org.apache.htrace; import java.lang.reflect.Constructor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A {@link SpanReceiver} builder. It reads a {@link SpanReceiver} class name from the provided * configuration using the {@link #SPAN_RECEIVER_CONF_KEY} key. Unqualified class names * are interpreted as members of the {@code org.apache.htrace.impl} package. The {@link #build()} * method constructs an instance of that class, initialized with the same configuration. */ public class SpanReceiverBuilder { static final Log LOG = LogFactory.getLog(SpanReceiverBuilder.class); public final static String SPAN_RECEIVER_CONF_KEY = "span.receiver"; private final static String DEFAULT_PACKAGE = "org.apache.htrace.impl"; private final static ClassLoader classLoader = SpanReceiverBuilder.class.getClassLoader(); private final HTraceConfiguration conf; private boolean logErrors; private String spanReceiverClass; public SpanReceiverBuilder(HTraceConfiguration conf) { this.conf = conf; reset(); } /** * Set this builder back to defaults. Any previous calls to {@link #spanReceiverClass(String)} * are overridden by the value provided by configuration. * @return This instance */ public SpanReceiverBuilder reset() { this.logErrors = true; this.spanReceiverClass = this.conf.get(SPAN_RECEIVER_CONF_KEY); return this; } /** * Override the {@code SpanReceiver} class name provided in configuration with a new value. * @return This instance */ public SpanReceiverBuilder spanReceiverClass(final String spanReceiverClass) { this.spanReceiverClass = spanReceiverClass; return this; } /** * Configure whether we should log errors during build(). * @return This instance */ public SpanReceiverBuilder logErrors(boolean logErrors) { this.logErrors = logErrors; return this; } private void logError(String errorStr) { if (!logErrors) { return; } LOG.error(errorStr); } private void logError(String errorStr, Throwable e) { if (!logErrors) { return; } LOG.error(errorStr, e); } public SpanReceiver build() { if ((this.spanReceiverClass == null) || this.spanReceiverClass.isEmpty()) { return null; } String str = spanReceiverClass; if (!str.contains(".")) { str = DEFAULT_PACKAGE + "." + str; } Class cls = null; try { cls = classLoader.loadClass(str); } catch (ClassNotFoundException e) { logError("SpanReceiverBuilder cannot find SpanReceiver class " + str + ": disabling span receiver."); return null; } Constructor ctor = null; try { ctor = cls.getConstructor(HTraceConfiguration.class); } catch (NoSuchMethodException e) { logError("SpanReceiverBuilder cannot find a constructor for class " + str + "which takes an HTraceConfiguration. Disabling span " + "receiver."); return null; } try { return ctor.newInstance(conf); } catch (ReflectiveOperationException e) { logError("SpanReceiverBuilder reflection error when constructing " + str + ". Disabling span receiver.", e); return null; } catch (Throwable e) { logError("SpanReceiverBuilder constructor error when constructing " + str + ". Disabling span receiver.", e); return null; } } }incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/TimelineAnnotation.java000066400000000000000000000022631245601110500315150ustar00rootroot00000000000000/* * 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 org.apache.htrace; public class TimelineAnnotation { private final long time; private final String msg; public TimelineAnnotation(long time, String msg) { this.time = time; this.msg = msg; } public long getTime() { return time; } public String getMessage() { return msg; } @Override public String toString() { return "@" + time + ": " + msg; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/Trace.java000066400000000000000000000142451245601110500267550ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.htrace.impl.MilliSpan; import org.apache.htrace.impl.TrueIfTracingSampler; import org.apache.htrace.wrappers.TraceCallable; import org.apache.htrace.wrappers.TraceRunnable; import java.security.SecureRandom; import java.util.Random; import java.util.concurrent.Callable; /** * The primary way to interact with the library. Provides methods to start * spans, as well as set necessary tracing information. */ public class Trace { private final static Random random = new SecureRandom(); /** * Starts and returns a new span as the child of the current span if the * default sampler (TrueIfTracingSampler) returns true, otherwise returns the * NullSpan. * * @param description Description of the span to be created. * @return */ public static TraceScope startSpan(String description) { return startSpan(description, TrueIfTracingSampler.INSTANCE); } /** * Starts and returns a new span as the child of the parameter 'parent'. This * will always return a new span, even if tracing wasn't previously enabled for * this thread. * * @param description Description of the span to be created. * @param parent The parent that should be used to create the child span that is to * be returned. * @return */ public static TraceScope startSpan(String description, Span parent) { if (parent == null) return startSpan(description); return continueSpan(parent.child(description)); } public static TraceScope startSpan(String description, TraceInfo tinfo) { if (tinfo == null) return continueSpan(null); Span newSpan = new MilliSpan(description, tinfo.traceId, tinfo.spanId, random.nextLong(), Tracer.getProcessId()); return continueSpan(newSpan); } public static TraceScope startSpan(String description, Sampler s) { return startSpan(description, s, null); } public static TraceScope startSpan(String description, Sampler s, TraceInfo tinfo) { Span span = null; if (isTracing() || s.next(tinfo)) { span = new MilliSpan(description, tinfo.traceId, tinfo.spanId, random.nextLong(), Tracer.getProcessId()); } return continueSpan(span); } public static TraceScope startSpan(String description, Sampler s, T info) { Span span = null; if (isTracing() || s.next(info)) { span = Tracer.getInstance().createNew(description); } return continueSpan(span); } /** * Pick up an existing span from another thread. */ public static TraceScope continueSpan(Span s) { // Return an empty TraceScope that does nothing on close if (s == null) return NullScope.INSTANCE; return Tracer.getInstance().continueSpan(s); } /** * Set the processId to be used for all Spans created by this Tracer. * * @param processId * @see Span.java */ public static void setProcessId(String processId) { Tracer.processId = processId; } /** * Removes the given SpanReceiver from the list of SpanReceivers. * * @param rcvr */ public static void removeReceiver(SpanReceiver rcvr) { Tracer.getInstance().removeReceiver(rcvr); } /** * Adds the given SpanReceiver to the current Tracer instance's list of * SpanReceivers. * * @param rcvr */ public static void addReceiver(SpanReceiver rcvr) { Tracer.getInstance().addReceiver(rcvr); } /** * Adds a data annotation to the current span if tracing is currently on. */ public static void addKVAnnotation(byte[] key, byte[] value) { Span s = currentSpan(); if (s != null) { s.addKVAnnotation(key, value); } } /** * Annotate the current span with the given message. */ public static void addTimelineAnnotation(String msg) { Span s = currentSpan(); if (s != null) { s.addTimelineAnnotation(msg); } } /** * Returns true if the current thread is a part of a trace, false otherwise. * * @return */ public static boolean isTracing() { return Tracer.getInstance().isTracing(); } /** * If we are tracing, return the current span, else null * * @return Span representing the current trace, or null if not tracing. */ public static Span currentSpan() { return Tracer.getInstance().currentSpan(); } /** * Wrap the callable in a TraceCallable, if tracing. * * @param callable * @return The callable provided, wrapped if tracing, 'callable' if not. */ public static Callable wrap(Callable callable) { if (isTracing()) { return new TraceCallable(Trace.currentSpan(), callable); } else { return callable; } } /** * Wrap the runnable in a TraceRunnable, if tracing * * @param runnable * @return The runnable provided, wrapped if tracing, 'runnable' if not. */ public static Runnable wrap(Runnable runnable) { if (isTracing()) { return new TraceRunnable(Trace.currentSpan(), runnable); } else { return runnable; } } /** * Wrap the runnable in a TraceRunnable, if tracing * * @param description name of the span to be created. * @param runnable * @return The runnable provided, wrapped if tracing, 'runnable' if not. */ public static Runnable wrap(String description, Runnable runnable) { if (isTracing()) { return new TraceRunnable(Trace.currentSpan(), runnable, description); } else { return runnable; } } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/TraceInfo.java000066400000000000000000000023771245601110500275740ustar00rootroot00000000000000/* * 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 org.apache.htrace; public class TraceInfo { public final long traceId; public final long spanId; public TraceInfo(long traceId, long spanId) { this.traceId = traceId; this.spanId = spanId; } @Override public String toString() { return "TraceInfo(traceId=" + traceId + ", spanId=" + spanId + ")"; } public static TraceInfo fromSpan(Span s) { if (s == null) return null; return new TraceInfo(s.getTraceId(), s.getSpanId()); } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/TraceScope.java000066400000000000000000000042231245601110500277420ustar00rootroot00000000000000/* * 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 org.apache.htrace; import java.io.Closeable; public class TraceScope implements Closeable { /** * the span for this scope */ private final Span span; /** * the span that was "current" before this scope was entered */ private final Span savedSpan; private boolean detached = false; TraceScope(Span span, Span saved) { this.span = span; this.savedSpan = saved; } public Span getSpan() { return span; } /** * Remove this span as the current thread, but don't stop it yet or * send it for collection. This is useful if the span object is then * passed to another thread for use with Trace.continueTrace(). * * @return the same Span object */ public Span detach() { detached = true; Span cur = Tracer.getInstance().currentSpan(); if (cur != span) { Tracer.LOG.debug("Closing trace span " + span + " but " + cur + " was top-of-stack"); } else { Tracer.getInstance().setCurrentSpan(savedSpan); } return span; } /** * Return true when {@link #detach()} has been called. Helpful when debugging * multiple threads working on a single span. */ public boolean isDetached() { return detached; } @Override public void close() { if (span == null) return; if (!detached) { // The span is done span.stop(); detach(); } } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/TraceTree.java000066400000000000000000000111541245601110500275710ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.htrace.impl.MilliSpan; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.TreeSet; /** * Used to create the graph formed by spans. */ public class TraceTree { public static final Log LOG = LogFactory.getLog(Tracer.class); public static class SpansByParent { private static Comparator COMPARATOR = new Comparator() { @Override public int compare(Span a, Span b) { if (a.getParentId() < b.getParentId()) { return -1; } else if (a.getParentId() > b.getParentId()) { return 1; } else if (a.getSpanId() < b.getSpanId()) { return -1; } else if (a.getSpanId() > b.getSpanId()) { return 1; } else { return 0; } } }; private final TreeSet treeSet; SpansByParent(Collection spans) { TreeSet treeSet = new TreeSet(COMPARATOR); for (Span span : spans) { treeSet.add(span); } this.treeSet = treeSet; } public List find(long parentId) { List spans = new ArrayList(); Span span = new MilliSpan("", Long.MIN_VALUE, parentId, Long.MIN_VALUE, ""); while (true) { span = treeSet.higher(span); if (span == null) { break; } if (span.getParentId() != parentId) { break; } spans.add(span); } return spans; } public Iterator iterator() { return Collections.unmodifiableSortedSet(treeSet).iterator(); } } public static class SpansByProcessId { private static Comparator COMPARATOR = new Comparator() { @Override public int compare(Span a, Span b) { int cmp = a.getProcessId().compareTo(b.getProcessId()); if (cmp != 0) { return cmp; } else if (a.getSpanId() < b.getSpanId()) { return -1; } else if (a.getSpanId() > b.getSpanId()) { return 1; } else { return 0; } } }; private final TreeSet treeSet; SpansByProcessId(Collection spans) { TreeSet treeSet = new TreeSet(COMPARATOR); for (Span span : spans) { treeSet.add(span); } this.treeSet = treeSet; } public List find(String processId) { List spans = new ArrayList(); Span span = new MilliSpan("", Long.MIN_VALUE, Long.MIN_VALUE, Long.MIN_VALUE, processId); while (true) { span = treeSet.higher(span); if (span == null) { break; } if (span.getProcessId().equals(processId)) { break; } spans.add(span); } return spans; } public Iterator iterator() { return Collections.unmodifiableSortedSet(treeSet).iterator(); } } private final SpansByParent spansByParent; private final SpansByProcessId spansByProcessId; /** * Create a new TraceTree * * @param spans The collection of spans to use to create this TraceTree. Should * have at least one root span (span with parentId = * Span.ROOT_SPAN_ID */ public TraceTree(Collection spans) { this.spansByParent = new SpansByParent(spans); this.spansByProcessId = new SpansByProcessId(spans); } public SpansByParent getSpansByParent() { return spansByParent; } public SpansByProcessId getSpansByProcessId() { return spansByProcessId; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/Tracer.java000066400000000000000000000072221245601110500271340ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.htrace.impl.MilliSpan; import java.security.SecureRandom; import java.util.List; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; /** * A Tracer provides the implementation for collecting and distributing Spans * within a process. */ public class Tracer { public static final Log LOG = LogFactory.getLog(Tracer.class); private final static Random random = new SecureRandom(); private final List receivers = new CopyOnWriteArrayList(); private static final ThreadLocal currentSpan = new ThreadLocal() { @Override protected Span initialValue() { return null; } }; public static final TraceInfo DONT_TRACE = new TraceInfo(-1, -1); protected static String processId = null; /** * Internal class for defered singleton idiom. *

* https://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom */ private static class TracerHolder { private static final Tracer INSTANCE = new Tracer(); } public static Tracer getInstance() { return TracerHolder.INSTANCE; } protected Span createNew(String description) { Span parent = currentSpan.get(); if (parent == null) { return new MilliSpan(description, /* traceId = */ random.nextLong(), /* parentSpanId = */ Span.ROOT_SPAN_ID, /* spanId = */ random.nextLong(), getProcessId()); } else { return parent.child(description); } } protected boolean isTracing() { return currentSpan.get() != null; } protected Span currentSpan() { return currentSpan.get(); } public void deliver(Span span) { for (SpanReceiver receiver : receivers) { receiver.receiveSpan(span); } } protected void addReceiver(SpanReceiver receiver) { receivers.add(receiver); } protected void removeReceiver(SpanReceiver receiver) { receivers.remove(receiver); } protected Span setCurrentSpan(Span span) { if (LOG.isTraceEnabled()) { LOG.trace("setting current span " + span); } currentSpan.set(span); return span; } public TraceScope continueSpan(Span s) { Span oldCurrent = currentSpan(); setCurrentSpan(s); return new TraceScope(s, oldCurrent); } protected int numReceivers() { return receivers.size(); } static String getProcessId() { if (processId == null) { String cmdLine = System.getProperty("sun.java.command"); if (cmdLine != null && !cmdLine.isEmpty()) { String fullClassName = cmdLine.split("\\s+")[0]; String[] classParts = fullClassName.split("\\."); cmdLine = classParts[classParts.length - 1]; } processId = (cmdLine == null || cmdLine.isEmpty()) ? "Unknown" : cmdLine; } return processId; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/000077500000000000000000000000001245601110500260075ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/AlwaysSampler.java000066400000000000000000000023131245601110500314350ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Sampler; /** * A Sampler that always returns true. */ public final class AlwaysSampler implements Sampler { public static final AlwaysSampler INSTANCE = new AlwaysSampler(null); public AlwaysSampler(HTraceConfiguration conf) { } @Override public boolean next(Object info) { return true; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/CountSampler.java000066400000000000000000000030451245601110500312700ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Sampler; import java.util.Random; /** * Sampler that returns true every N calls. Specify the frequency interval by configuring a * {@code long} value for {@link #SAMPLER_FREQUENCY_CONF_KEY}. */ public class CountSampler implements Sampler { public final static String SAMPLER_FREQUENCY_CONF_KEY = "sampler.frequency"; final static Random random = new Random(); final long frequency; long count = random.nextLong(); public CountSampler(HTraceConfiguration conf) { this.frequency = Long.parseLong(conf.get(SAMPLER_FREQUENCY_CONF_KEY), 10); } @Override public boolean next(Object info) { return (count++ % frequency) == 0; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/LocalFileSpanReceiver.java000066400000000000000000000100241245601110500330100ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Writes the spans it receives to a local file. * A production LocalFileSpanReceiver should use a real CSV format. */ public class LocalFileSpanReceiver implements SpanReceiver { public static final Log LOG = LogFactory.getLog(LocalFileSpanReceiver.class); public static final String PATH_KEY = "local-file-span-receiver.path"; public static final String CAPACITY_KEY = "local-file-span-receiver.capacity"; // default capacity for the executors blocking queue public static final int CAPACITY_DEFAULT = 5000; // default timeout duration when calling executor.awaitTermination() public static final long EXECUTOR_TERMINATION_TIMEOUT_DURATION_DEFAULT = 60; private String file; private FileWriter fwriter; private BufferedWriter bwriter; private ExecutorService executor; private long executorTerminationTimeoutDuration; public LocalFileSpanReceiver(HTraceConfiguration conf) { this.executorTerminationTimeoutDuration = EXECUTOR_TERMINATION_TIMEOUT_DURATION_DEFAULT; int capacity = conf.getInt(CAPACITY_KEY, CAPACITY_DEFAULT); this.file = conf.get(PATH_KEY); if (file == null || file.isEmpty()) { throw new IllegalArgumentException("must configure " + PATH_KEY); } this.executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue(capacity)); try { this.fwriter = new FileWriter(this.file, true); } catch (IOException ioe) { throw new RuntimeException(ioe); } this.bwriter = new BufferedWriter(fwriter); } private class WriteSpanRunnable implements Runnable { public final Span span; public WriteSpanRunnable(Span span) { this.span = span; } @Override public void run() { try { bwriter.write(span.toJson()); bwriter.newLine(); bwriter.flush(); } catch (IOException e) { LOG.error("Error when writing to file: " + file, e); } } } @Override public void receiveSpan(Span span) { executor.submit(new WriteSpanRunnable(span)); } @Override public void close() throws IOException { executor.shutdown(); try { if (!executor.awaitTermination(this.executorTerminationTimeoutDuration, TimeUnit.SECONDS)) { LOG.warn("Was not able to process all remaining spans to write upon closing in: " + this.executorTerminationTimeoutDuration + "s"); } } catch (InterruptedException e1) { LOG.warn("Thread interrupted when terminating executor.", e1); } try { fwriter.close(); } catch (IOException e) { LOG.error("Error closing filewriter for file: " + file, e); } try { bwriter.close(); } catch (IOException e) { LOG.error("Error closing bufferedwriter for file: " + file, e); } } }incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/MilliSpan.java000066400000000000000000000226141245601110500305470ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import org.apache.htrace.Span; import org.apache.htrace.TimelineAnnotation; import org.apache.htrace.Tracer; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.StringWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; /** * A Span implementation that stores its information in milliseconds since the * epoch. */ @JsonDeserialize(using = MilliSpan.MilliSpanDeserializer.class) public class MilliSpan implements Span { private static Random rand = new Random(); private static ObjectWriter JSON_WRITER = new ObjectMapper().writer(); private long begin; private long end; private final String description; private final long traceId; private final long parents[]; private final long spanId; private Map traceInfo = null; private final String processId; private List timeline = null; @Override public Span child(String description) { return new MilliSpan(description, traceId, spanId, rand.nextLong(), processId); } /** * The public interface for constructing a MilliSpan. */ public static class Builder { private long begin; private long end; private String description; private long traceId; private long parents[]; private long spanId; private Map traceInfo = null; private String processId; private List timeline = null; public Builder() { } public Builder begin(long begin) { this.begin = begin; return this; } public Builder end(long end) { this.end = end; return this; } public Builder description(String description) { this.description = description; return this; } public Builder traceId(long traceId) { this.traceId = traceId; return this; } public Builder parents(long parents[]) { this.parents = parents; return this; } public Builder parents(List parentList) { long[] parents = new long[parentList.size()]; for (int i = 0; i < parentList.size(); i++) { parents[i] = parentList.get(i).longValue(); } this.parents = parents; return this; } public Builder spanId(long spanId) { this.spanId = spanId; return this; } public Builder traceInfo(Map traceInfo) { this.traceInfo = traceInfo.isEmpty() ? null : traceInfo; return this; } public Builder processId(String processId) { this.processId = processId; return this; } public Builder timeline(List timeline) { this.timeline = timeline.isEmpty() ? null : timeline; return this; } public MilliSpan build() { return new MilliSpan(this); } } private MilliSpan(Builder builder) { this.begin = builder.begin; this.end = builder.end; this.description = builder.description; this.traceId = builder.traceId; this.parents = builder.parents; this.spanId = builder.spanId; this.traceInfo = builder.traceInfo; this.processId = builder.processId; this.timeline = builder.timeline; } public MilliSpan(String description, long traceId, long parentSpanId, long spanId, String processId) { this.description = description; this.traceId = traceId; if (parentSpanId == Span.ROOT_SPAN_ID) { this.parents = new long[0]; } else { this.parents = new long[] { parentSpanId }; } this.spanId = spanId; this.begin = System.currentTimeMillis(); this.end = 0; this.processId = processId; } @Override public synchronized void stop() { if (end == 0) { if (begin == 0) throw new IllegalStateException("Span for " + description + " has not been started"); end = System.currentTimeMillis(); Tracer.getInstance().deliver(this); } } protected long currentTimeMillis() { return System.currentTimeMillis(); } @Override public synchronized boolean isRunning() { return begin != 0 && end == 0; } @Override public synchronized long getAccumulatedMillis() { if (begin == 0) return 0; if (end > 0) return end - begin; return currentTimeMillis() - begin; } @Override public String toString() { return toJson(); } @Override public String getDescription() { return description; } @Override public long getSpanId() { return spanId; } // TODO: Fix API callers to deal with multiple parents, and get rid of // Span.ROOT_SPAN_ID. @Override public long getParentId() { if (parents.length == 0) { return Span.ROOT_SPAN_ID; } return parents[0]; } @Override public long getTraceId() { return traceId; } @Override public long getStartTimeMillis() { return begin; } @Override public long getStopTimeMillis() { return end; } @Override public void addKVAnnotation(byte[] key, byte[] value) { if (traceInfo == null) traceInfo = new HashMap(); traceInfo.put(key, value); } @Override public void addTimelineAnnotation(String msg) { if (timeline == null) { timeline = new ArrayList(); } timeline.add(new TimelineAnnotation(System.currentTimeMillis(), msg)); } @Override public Map getKVAnnotations() { if (traceInfo == null) return Collections.emptyMap(); return Collections.unmodifiableMap(traceInfo); } @Override public List getTimelineAnnotations() { if (timeline == null) { return Collections.emptyList(); } return Collections.unmodifiableList(timeline); } @Override public String getProcessId() { return processId; } @Override public String toJson() { StringWriter writer = new StringWriter(); try { JSON_WRITER.writeValue(writer, this); } catch (IOException e) { // An IOException should not be possible when writing to a string. throw new RuntimeException(e); } return writer.toString(); } private static long parseUnsignedHexLong(String s) { return new BigInteger(s, 16).longValue(); } public static class MilliSpanDeserializer extends JsonDeserializer { @Override public MilliSpan deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode root = jp.getCodec().readTree(jp); Builder builder = new Builder(); builder.begin(root.get("b").asLong()). end(root.get("e").asLong()). description(root.get("d").asText()). traceId(parseUnsignedHexLong(root.get("i").asText())). spanId(parseUnsignedHexLong(root.get("s").asText())). processId(root.get("r").asText()); JsonNode parentsNode = root.get("p"); LinkedList parents = new LinkedList(); for (Iterator iter = parentsNode.elements(); iter.hasNext(); ) { JsonNode parentIdNode = iter.next(); parents.add(parseUnsignedHexLong(parentIdNode.asText())); } builder.parents(parents); JsonNode traceInfoNode = root.get("n"); if (traceInfoNode != null) { HashMap traceInfo = new HashMap(); for (Iterator iter = traceInfoNode.fieldNames(); iter.hasNext(); ) { String field = iter.next(); traceInfo.put(field.getBytes("UTF-8"), traceInfoNode.get(field).asText().getBytes("UTF-8")); } builder.traceInfo(traceInfo); } JsonNode timelineNode = root.get("t"); if (timelineNode != null) { LinkedList timeline = new LinkedList(); for (Iterator iter = timelineNode.elements(); iter.hasNext(); ) { JsonNode ann = iter.next(); timeline.add(new TimelineAnnotation(ann.get("t").asLong(), ann.get("m").asText())); } builder.timeline(timeline); } return builder.build(); } } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/NeverSampler.java000066400000000000000000000023101245601110500312510ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Sampler; /** * A Sampler that never returns true. */ public final class NeverSampler implements Sampler { public static final NeverSampler INSTANCE = new NeverSampler(null); public NeverSampler(HTraceConfiguration conf) { } @Override public boolean next(Object info) { return false; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/POJOSpanReceiver.java000066400000000000000000000031611245601110500317310ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import java.io.IOException; import java.util.Collection; import java.util.HashSet; /** * SpanReceiver for testing only that just collects the Span objects it * receives. The spans it receives can be accessed with getSpans(); */ public class POJOSpanReceiver implements SpanReceiver { private final Collection spans; public POJOSpanReceiver(HTraceConfiguration conf) { this.spans = new HashSet(); } /** * @return The spans this POJOSpanReceiver has received. */ public Collection getSpans() { return spans; } @Override public void close() throws IOException { } @Override public void receiveSpan(Span span) { spans.add(span); } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/ProbabilitySampler.java000066400000000000000000000030471245601110500324620ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Sampler; import java.util.Random; /** * Sampler that returns true a certain percentage of the time. Specify the frequency interval by * configuring a {@code double} value for {@link #SAMPLER_FRACTION_CONF_KEY}. */ public class ProbabilitySampler implements Sampler { public final double threshold; private Random random = new Random(); public final static String SAMPLER_FRACTION_CONF_KEY = "sampler.fraction"; public ProbabilitySampler(HTraceConfiguration conf) { this.threshold = Double.parseDouble(conf.get(SAMPLER_FRACTION_CONF_KEY)); } @Override public boolean next(Object info) { return random.nextDouble() < threshold; } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/StandardOutSpanReceiver.java000066400000000000000000000024731245601110500334170ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import java.io.IOException; /** * Used for testing. Simply prints to standard out any spans it receives. */ public class StandardOutSpanReceiver implements SpanReceiver { public StandardOutSpanReceiver(HTraceConfiguration conf) { } @Override public void receiveSpan(Span span) { System.out.println(span); } @Override public void close() throws IOException { } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/impl/TrueIfTracingSampler.java000066400000000000000000000025051245601110500327060ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Sampler; import org.apache.htrace.Trace; /** * A Sampler that returns true if and only if tracing is enabled for the current thread. */ public class TrueIfTracingSampler implements Sampler { public static final TrueIfTracingSampler INSTANCE = new TrueIfTracingSampler(null); public TrueIfTracingSampler(HTraceConfiguration conf) { } @Override public boolean next(Object info) { return Trace.isTracing(); } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/wrappers/000077500000000000000000000000001245601110500267115ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/wrappers/TraceCallable.java000066400000000000000000000037371245601110500322440ustar00rootroot00000000000000/* * 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 org.apache.htrace.wrappers; import org.apache.htrace.Span; import org.apache.htrace.Trace; import org.apache.htrace.TraceScope; import java.util.concurrent.Callable; /** * Wrap a Callable with a Span that survives a change in threads. */ public class TraceCallable implements Callable { private final Callable impl; private final Span parent; private final String description; public TraceCallable(Callable impl) { this(Trace.currentSpan(), impl); } public TraceCallable(Span parent, Callable impl) { this(parent, impl, null); } public TraceCallable(Span parent, Callable impl, String description) { this.impl = impl; this.parent = parent; this.description = description; } @Override public V call() throws Exception { if (parent != null) { TraceScope chunk = Trace.startSpan(getDescription(), parent); try { return impl.call(); } finally { chunk.close(); } } else { return impl.call(); } } public Callable getImpl() { return impl; } private String getDescription() { return this.description == null ? Thread.currentThread().getName() : description; } } TraceExecutorService.java000066400000000000000000000066511245601110500336030ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/wrappers/* * 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 org.apache.htrace.wrappers; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class TraceExecutorService implements ExecutorService { private final ExecutorService impl; public TraceExecutorService(ExecutorService impl) { this.impl = impl; } @Override public void execute(Runnable command) { impl.execute(new TraceRunnable(command)); } @Override public void shutdown() { impl.shutdown(); } @Override public List shutdownNow() { return impl.shutdownNow(); } @Override public boolean isShutdown() { return impl.isShutdown(); } @Override public boolean isTerminated() { return impl.isTerminated(); } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return impl.awaitTermination(timeout, unit); } @Override public Future submit(Callable task) { return impl.submit(new TraceCallable(task)); } @Override public Future submit(Runnable task, T result) { return impl.submit(new TraceRunnable(task), result); } @Override public Future submit(Runnable task) { return impl.submit(new TraceRunnable(task)); } private Collection> wrapCollection( Collection> tasks) { List> result = new ArrayList>(); for (Callable task : tasks) { result.add(new TraceCallable(task)); } return result; } @Override public List> invokeAll(Collection> tasks) throws InterruptedException { return impl.invokeAll(wrapCollection(tasks)); } @Override public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { return impl.invokeAll(wrapCollection(tasks), timeout, unit); } @Override public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { return impl.invokeAny(wrapCollection(tasks)); } @Override public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return impl.invokeAny(wrapCollection(tasks), timeout, unit); } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/wrappers/TraceProxy.java000066400000000000000000000042741245601110500316630ustar00rootroot00000000000000/* * 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 org.apache.htrace.wrappers; import org.apache.htrace.Sampler; import org.apache.htrace.Trace; import org.apache.htrace.TraceScope; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class TraceProxy { /** * Returns an object that will trace all calls to itself. * * @param instance * @return */ public static T trace(T instance) { return trace(instance, Sampler.ALWAYS); } /** * Returns an object that will trace all calls to itself. * * @param * @param instance * @param sampler * @return */ @SuppressWarnings("unchecked") public static T trace(final T instance, final Sampler sampler) { InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object obj, Method method, Object[] args) throws Throwable { if (!sampler.next(null)) { return method.invoke(instance, args); } TraceScope scope = Trace.startSpan(method.getName(), Sampler.ALWAYS); try { return method.invoke(instance, args); } catch (Throwable ex) { ex.printStackTrace(); throw ex; } finally { scope.close(); } } }; return (T) Proxy.newProxyInstance(instance.getClass().getClassLoader(), instance.getClass().getInterfaces(), handler); } } incubator-htrace-3.1.0/htrace-core/src/main/java/org/apache/htrace/wrappers/TraceRunnable.java000066400000000000000000000036651245601110500323130ustar00rootroot00000000000000/* * 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 org.apache.htrace.wrappers; import org.apache.htrace.Span; import org.apache.htrace.Trace; import org.apache.htrace.TraceScope; /** * Wrap a Runnable with a Span that survives a change in threads. */ public class TraceRunnable implements Runnable { private final Span parent; private final Runnable runnable; private final String description; public TraceRunnable(Runnable runnable) { this(Trace.currentSpan(), runnable); } public TraceRunnable(Span parent, Runnable runnable) { this(parent, runnable, null); } public TraceRunnable(Span parent, Runnable runnable, String description) { this.parent = parent; this.runnable = runnable; this.description = description; } @Override public void run() { if (parent != null) { TraceScope chunk = Trace.startSpan(getDescription(), parent); try { runnable.run(); } finally { chunk.close(); } } else { runnable.run(); } } private String getDescription() { return this.description == null ? Thread.currentThread().getName() : description; } public Runnable getRunnable() { return runnable; } } incubator-htrace-3.1.0/htrace-core/src/test/000077500000000000000000000000001245601110500207025ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/test/java/000077500000000000000000000000001245601110500216235ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/test/java/org/000077500000000000000000000000001245601110500224125ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/000077500000000000000000000000001245601110500236335ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/000077500000000000000000000000001245601110500251015ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/TestCountSampler.java000066400000000000000000000030241245601110500312170ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.impl.CountSampler; import org.junit.Assert; import org.junit.Test; public class TestCountSampler { @Test public void testNext() { CountSampler half = new CountSampler(HTraceConfiguration. fromKeyValuePairs("sampler.frequency", "2")); CountSampler hundred = new CountSampler(HTraceConfiguration. fromKeyValuePairs("sampler.frequency", "100")); int halfCount = 0; int hundredCount = 0; for (int i = 0; i < 200; i++) { if (half.next(null)) halfCount++; if (hundred.next(null)) hundredCount++; } Assert.assertEquals(2, hundredCount); Assert.assertEquals(100, halfCount); } } incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/TestHTrace.java000066400000000000000000000105361245601110500277570ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import org.apache.htrace.TraceTree; import org.apache.htrace.TraceTree.SpansByParent; import org.apache.htrace.impl.LocalFileSpanReceiver; import org.apache.htrace.impl.POJOSpanReceiver; import org.apache.htrace.impl.StandardOutSpanReceiver; import org.junit.Assert; import org.junit.Test; import java.io.File; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; public class TestHTrace { public static final String SPAN_FILE_FLAG = "spanFile"; /** * Basic system test of HTrace. * * @throws Exception */ @Test public void testHtrace() throws Exception { final int numTraces = 3; String fileName = System.getProperty(SPAN_FILE_FLAG); Collection rcvrs = new HashSet(); // writes spans to a file if one is provided to maven with // -DspanFile="FILENAME", otherwise writes to standard out. if (fileName != null) { File f = new File(fileName); File parent = f.getParentFile(); if (parent != null && !parent.exists() && !parent.mkdirs()) { throw new IllegalArgumentException("Couldn't create file: " + fileName); } HashMap conf = new HashMap(); conf.put("local-file-span-receiver.path", fileName); LocalFileSpanReceiver receiver = new LocalFileSpanReceiver(HTraceConfiguration.fromMap(conf)); rcvrs.add(receiver); } else { rcvrs.add(new StandardOutSpanReceiver(HTraceConfiguration.EMPTY)); } POJOSpanReceiver psr = new POJOSpanReceiver(HTraceConfiguration.EMPTY); rcvrs.add(psr); runTraceCreatorTraces(new TraceCreator(rcvrs)); for (SpanReceiver receiver : rcvrs) { receiver.close(); } Collection spans = psr.getSpans(); TraceTree traceTree = new TraceTree(spans); Collection roots = traceTree.getSpansByParent().find(Span.ROOT_SPAN_ID); Assert.assertTrue("Trace tree must have roots", !roots.isEmpty()); Assert.assertEquals(numTraces, roots.size()); Map descriptionToRootSpan = new HashMap(); for (Span root : roots) { descriptionToRootSpan.put(root.getDescription(), root); } Assert.assertTrue(descriptionToRootSpan.keySet().contains( TraceCreator.RPC_TRACE_ROOT)); Assert.assertTrue(descriptionToRootSpan.keySet().contains( TraceCreator.SIMPLE_TRACE_ROOT)); Assert.assertTrue(descriptionToRootSpan.keySet().contains( TraceCreator.THREADED_TRACE_ROOT)); SpansByParent spansByParentId = traceTree.getSpansByParent(); Span rpcTraceRoot = descriptionToRootSpan.get(TraceCreator.RPC_TRACE_ROOT); Assert.assertEquals(1, spansByParentId.find(rpcTraceRoot.getSpanId()).size()); Span rpcTraceChild1 = spansByParentId.find(rpcTraceRoot.getSpanId()) .iterator().next(); Assert.assertEquals(1, spansByParentId.find(rpcTraceChild1.getSpanId()).size()); Span rpcTraceChild2 = spansByParentId.find(rpcTraceChild1.getSpanId()) .iterator().next(); Assert.assertEquals(1, spansByParentId.find(rpcTraceChild2.getSpanId()).size()); Span rpcTraceChild3 = spansByParentId.find(rpcTraceChild2.getSpanId()) .iterator().next(); Assert.assertEquals(0, spansByParentId.find(rpcTraceChild3.getSpanId()).size()); } private void runTraceCreatorTraces(TraceCreator tc) { tc.createThreadedTrace(); tc.createSimpleTrace(); tc.createSampleRpcTrace(); } } incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/TestHTraceConfiguration.java000066400000000000000000000043101245601110500325000ustar00rootroot00000000000000/* * 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 org.apache.htrace; import java.util.HashMap; import java.util.Map; import org.apache.htrace.HTraceConfiguration; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class TestHTraceConfiguration { @Test public void testGetBoolean() throws Exception { Map m = new HashMap(); m.put("testTrue", " True"); m.put("testFalse", "falsE "); HTraceConfiguration configuration = HTraceConfiguration.fromMap(m); // Tests for value being there assertTrue(configuration.getBoolean("testTrue", false)); assertFalse(configuration.getBoolean("testFalse", true)); // Test for absent assertTrue(configuration.getBoolean("absent", true)); assertFalse(configuration.getBoolean("absent", false)); } @Test public void testGetInt() throws Exception { Map m = new HashMap(); m.put("a", "100"); m.put("b", "0"); m.put("c", "-100"); m.put("d", "5"); HTraceConfiguration configuration = HTraceConfiguration.fromMap(m); assertEquals(100, configuration.getInt("a", -999)); assertEquals(0, configuration.getInt("b", -999)); assertEquals(-100, configuration.getInt("c", -999)); assertEquals(5, configuration.getInt("d", -999)); assertEquals(-999, configuration.getInt("absent", -999)); } } incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/TestSampler.java000066400000000000000000000047141245601110500302150ustar00rootroot00000000000000/* * 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 org.apache.htrace; import java.util.HashMap; import java.util.Map; import org.apache.htrace.Sampler; import org.apache.htrace.Trace; import org.apache.htrace.TraceInfo; import org.apache.htrace.TraceScope; import org.apache.htrace.impl.AlwaysSampler; import org.apache.htrace.impl.NeverSampler; import org.junit.Assert; import org.junit.Test; public class TestSampler { @Test public void testSamplerBuilder() { Sampler alwaysSampler = new SamplerBuilder( HTraceConfiguration.fromKeyValuePairs("sampler", "AlwaysSampler")). build(); Assert.assertEquals(AlwaysSampler.class, alwaysSampler.getClass()); Sampler neverSampler = new SamplerBuilder( HTraceConfiguration.fromKeyValuePairs("sampler", "NeverSampler")). build(); Assert.assertEquals(NeverSampler.class, neverSampler.getClass()); Sampler neverSampler2 = new SamplerBuilder(HTraceConfiguration. fromKeyValuePairs("sampler", "NonExistentSampler")). build(); Assert.assertEquals(NeverSampler.class, neverSampler2.getClass()); } @Test public void testParamterizedSampler() { TestParamSampler sampler = new TestParamSampler(); TraceScope s = Trace.startSpan("test", sampler, 1); Assert.assertNotNull(s.getSpan()); s.close(); s = Trace.startSpan("test", sampler, -1); Assert.assertNull(s.getSpan()); s.close(); } @Test public void testAlwaysSampler() { TraceScope cur = Trace.startSpan("test", new TraceInfo(0, 0)); Assert.assertNotNull(cur); cur.close(); } private class TestParamSampler implements Sampler { @Override public boolean next(Integer info) { return info > 0; } } } incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/TestSpanReceiverBuilder.java000066400000000000000000000101671245601110500325060ustar00rootroot00000000000000/* * 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 org.apache.htrace; import org.apache.htrace.impl.LocalFileSpanReceiver; import org.junit.Assert; import org.junit.Test; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class TestSpanReceiverBuilder { /** * Test that if no span receiver is configured, the builder returns null. */ @Test public void testGetNullSpanReceiver() { SpanReceiverBuilder builder = new SpanReceiverBuilder(HTraceConfiguration.EMPTY).logErrors(false); SpanReceiver rcvr = builder.build(); Assert.assertEquals(null, rcvr); } private static SpanReceiver createSpanReceiver(Map m) { HTraceConfiguration hconf = HTraceConfiguration.fromMap(m); SpanReceiverBuilder builder = new SpanReceiverBuilder(hconf). logErrors(false); return builder.build(); } /** * Test getting various SpanReceiver objects. */ @Test public void testGetSpanReceivers() throws Exception { HashMap confMap = new HashMap(); // Create LocalFileSpanReceiver confMap.put(LocalFileSpanReceiver.PATH_KEY, "/tmp/foo"); confMap.put(SpanReceiverBuilder.SPAN_RECEIVER_CONF_KEY, "org.apache.htrace.impl.LocalFileSpanReceiver"); SpanReceiver rcvr = createSpanReceiver(confMap); Assert.assertEquals("org.apache.htrace.impl.LocalFileSpanReceiver", rcvr.getClass().getName()); rcvr.close(); // Create POJOSpanReceiver confMap.remove(LocalFileSpanReceiver.PATH_KEY); confMap.put(SpanReceiverBuilder.SPAN_RECEIVER_CONF_KEY, "POJOSpanReceiver"); rcvr = createSpanReceiver(confMap); Assert.assertEquals("org.apache.htrace.impl.POJOSpanReceiver", rcvr.getClass().getName()); rcvr.close(); // Create StandardOutSpanReceiver confMap.remove(LocalFileSpanReceiver.PATH_KEY); confMap.put(SpanReceiverBuilder.SPAN_RECEIVER_CONF_KEY, "org.apache.htrace.impl.StandardOutSpanReceiver"); rcvr = createSpanReceiver(confMap); Assert.assertEquals("org.apache.htrace.impl.StandardOutSpanReceiver", rcvr.getClass().getName()); rcvr.close(); } public static class TestSpanReceiver implements SpanReceiver { final static String SUCCEEDS = "test.span.receiver.succeeds"; public TestSpanReceiver(HTraceConfiguration conf) { if (conf.get(SUCCEEDS) == null) { throw new RuntimeException("Can't create TestSpanReceiver: " + "invalid configuration."); } } @Override public void receiveSpan(Span span) { } @Override public void close() throws IOException { } } /** * Test trying to create a SpanReceiver that experiences an error in the * constructor. */ @Test public void testGetSpanReceiverWithConstructorError() throws Exception { HashMap confMap = new HashMap(); // Create TestSpanReceiver confMap.put(SpanReceiverBuilder.SPAN_RECEIVER_CONF_KEY, TestSpanReceiver.class.getName()); confMap.put(TestSpanReceiver.SUCCEEDS, "true"); SpanReceiver rcvr = createSpanReceiver(confMap); Assert.assertEquals(TestSpanReceiver.class.getName(), rcvr.getClass().getName()); rcvr.close(); // Fail to create TestSpanReceiver confMap.remove(TestSpanReceiver.SUCCEEDS); rcvr = createSpanReceiver(confMap); Assert.assertEquals(null, rcvr); } } incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/TraceCreator.java000066400000000000000000000110301245601110500303150ustar00rootroot00000000000000/* * 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 org.apache.htrace; import java.util.Collection; import java.util.Random; import org.apache.htrace.Sampler; import org.apache.htrace.SpanReceiver; import org.apache.htrace.Trace; import org.apache.htrace.TraceInfo; import org.apache.htrace.TraceScope; /** * Does some stuff and traces it. */ public class TraceCreator { public static final String RPC_TRACE_ROOT = "createSampleRpcTrace"; public static final String THREADED_TRACE_ROOT = "createThreadedTrace"; public static final String SIMPLE_TRACE_ROOT = "createSimpleTrace"; /** * Takes as input the SpanReceiver that should used as the sink for Spans when * createDemoTrace() is called. * * @param receiver */ public TraceCreator(SpanReceiver receiver) { Trace.addReceiver(receiver); } /** * Takes as input the SpanReceivers that should used as the sink for Spans * when createDemoTrace() is called. * * @param receivers */ public TraceCreator(Collection receivers) { for (SpanReceiver receiver : receivers) { Trace.addReceiver(receiver); } } public void createSampleRpcTrace() { TraceScope s = Trace.startSpan(RPC_TRACE_ROOT, Sampler.ALWAYS); try { pretendRpcSend(); } finally { s.close(); } } public void createSimpleTrace() { TraceScope s = Trace.startSpan(SIMPLE_TRACE_ROOT, Sampler.ALWAYS); try { importantWork1(); } finally { s.close(); } } /** * Creates the demo trace (will create different traces from call to call). */ public void createThreadedTrace() { TraceScope s = Trace.startSpan(THREADED_TRACE_ROOT, Sampler.ALWAYS); try { Random r = new Random(); int numThreads = r.nextInt(4) + 1; Thread[] threads = new Thread[numThreads]; for (int i = 0; i < numThreads; i++) { threads[i] = new Thread(Trace.wrap(new MyRunnable())); } for (int i = 0; i < numThreads; i++) { threads[i].start(); } for (int i = 0; i < numThreads; i++) { try { threads[i].join(); } catch (InterruptedException e) { } } importantWork1(); } finally { s.close(); } } private void importantWork1() { TraceScope cur = Trace.startSpan("important work 1"); try { Thread.sleep((long) (2000 * Math.random())); importantWork2(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { cur.close(); } } private void importantWork2() { TraceScope cur = Trace.startSpan("important work 2"); try { Thread.sleep((long) (2000 * Math.random())); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { cur.close(); } } private class MyRunnable implements Runnable { @Override public void run() { try { Thread.sleep(750); Random r = new Random(); int importantNumber = 100 / r.nextInt(3); System.out.println("Important number: " + importantNumber); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } catch (ArithmeticException ae) { TraceScope c = Trace.startSpan("dealing with arithmetic exception."); try { Thread.sleep((long) (3000 * Math.random())); } catch (InterruptedException ie1) { Thread.currentThread().interrupt(); } finally { c.close(); } } } } public void pretendRpcSend() { pretendRpcReceiveWithTraceInfo(TraceInfo.fromSpan(Trace.currentSpan())); } public void pretendRpcReceiveWithTraceInfo(TraceInfo traceInfo) { TraceScope s = Trace.startSpan("received RPC", traceInfo); try { importantWork1(); } finally { s.close(); } } }incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/impl/000077500000000000000000000000001245601110500260425ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/test/java/org/apache/htrace/impl/TestMilliSpan.java000066400000000000000000000135341245601110500314430ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import com.fasterxml.jackson.databind.ObjectMapper; import static org.junit.Assert.assertEquals; import org.apache.htrace.Span; import org.apache.htrace.TimelineAnnotation; import org.junit.Test; import java.security.SecureRandom; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; public class TestMilliSpan { private void compareSpans(Span expected, Span got) throws Exception { assertEquals(expected.getStartTimeMillis(), got.getStartTimeMillis()); assertEquals(expected.getStopTimeMillis(), got.getStopTimeMillis()); assertEquals(expected.getDescription(), got.getDescription()); assertEquals(expected.getTraceId(), got.getTraceId()); assertEquals(expected.getSpanId(), got.getSpanId()); assertEquals(expected.getProcessId(), got.getProcessId()); assertEquals(expected.getParentId(), got.getParentId()); Map expectedT = expected.getKVAnnotations(); Map gotT = got.getKVAnnotations(); if (expectedT == null) { assertEquals(null, gotT); } else { assertEquals(expectedT.size(), gotT.size()); Map expectedTMap = new HashMap(); for (byte[] key : expectedT.keySet()) { expectedTMap.put(new String(key, "UTF-8"), new String(expectedT.get(key), "UTF-8")); } Map gotTMap = new HashMap(); for (byte[] key : gotT.keySet()) { gotTMap.put(new String(key, "UTF-8"), new String(gotT.get(key), "UTF-8")); } for (String key : expectedTMap.keySet()) { assertEquals(expectedTMap.get(key), gotTMap.get(key)); } } List expectedTimeline = expected.getTimelineAnnotations(); List gotTimeline = got.getTimelineAnnotations(); if (expectedTimeline == null) { assertEquals(null, gotTimeline); } else { assertEquals(expectedTimeline.size(), gotTimeline.size()); Iterator iter = gotTimeline.iterator(); for (TimelineAnnotation expectedAnn : expectedTimeline) { TimelineAnnotation gotAnn = iter.next(); assertEquals(expectedAnn.getMessage(), gotAnn.getMessage()); assertEquals(expectedAnn.getTime(), gotAnn.getTime()); } } } @Test public void testJsonSerialization() throws Exception { MilliSpan span = new MilliSpan.Builder(). description("foospan"). begin(123L). end(456L). parents(new long[] { 7L }). processId("b2404.halxg.com:8080"). spanId(989L). traceId(444).build(); String json = span.toJson(); ObjectMapper mapper = new ObjectMapper(); MilliSpan dspan = mapper.readValue(json, MilliSpan.class); compareSpans(span, dspan); } @Test public void testJsonSerializationWithNegativeLongValue() throws Exception { MilliSpan span = new MilliSpan.Builder(). description("foospan"). begin(-1L). end(-1L). parents(new long[] { -1L }). processId("b2404.halxg.com:8080"). spanId(-1L). traceId(-1L).build(); String json = span.toJson(); ObjectMapper mapper = new ObjectMapper(); MilliSpan dspan = mapper.readValue(json, MilliSpan.class); compareSpans(span, dspan); } @Test public void testJsonSerializationWithRandomLongValue() throws Exception { Random random = new SecureRandom(); MilliSpan span = new MilliSpan.Builder(). description("foospan"). begin(random.nextLong()). end(random.nextLong()). parents(new long[] { random.nextLong() }). processId("b2404.halxg.com:8080"). spanId(random.nextLong()). traceId(random.nextLong()).build(); String json = span.toJson(); ObjectMapper mapper = new ObjectMapper(); MilliSpan dspan = mapper.readValue(json, MilliSpan.class); compareSpans(span, dspan); } @Test public void testJsonSerializationWithOptionalFields() throws Exception { MilliSpan.Builder builder = new MilliSpan.Builder(). description("foospan"). begin(300). end(400). parents(new long[] { }). processId("b2408.halxg.com:8080"). spanId(111111111L). traceId(4443); Map traceInfo = new HashMap(); traceInfo.put("abc".getBytes("UTF-8"), "123".getBytes("UTF-8")); traceInfo.put("def".getBytes("UTF-8"), "456".getBytes("UTF-8")); builder.traceInfo(traceInfo); List timeline = new LinkedList(); timeline.add(new TimelineAnnotation(310L, "something happened")); timeline.add(new TimelineAnnotation(380L, "something else happened")); timeline.add(new TimelineAnnotation(390L, "more things")); builder.timeline(timeline); MilliSpan span = builder.build(); String json = span.toJson(); ObjectMapper mapper = new ObjectMapper(); MilliSpan dspan = mapper.readValue(json, MilliSpan.class); compareSpans(span, dspan); } } incubator-htrace-3.1.0/htrace-core/src/web/000077500000000000000000000000001245601110500205005ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/web/index.html000066400000000000000000000020121245601110500224700ustar00rootroot00000000000000 HTRACE Hello, world.

incubator-htrace-3.1.0/htrace-core/src/web/nested/000077500000000000000000000000001245601110500217625ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-core/src/web/nested/nested.html000066400000000000000000000020121245601110500241250ustar00rootroot00000000000000 HTRACE Nested world.

incubator-htrace-3.1.0/htrace-flume/000077500000000000000000000000001245601110500173145ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/README.md000066400000000000000000000050441245601110500205760ustar00rootroot00000000000000 htrace-flume ============ htrace-flume provides the span receiver which sends tracing spans to Flume collector. Tutorial -------- 1) build and deploy $ cd htrace/htrace-flume $ mvn compile assembly:single $ cp target/htrace-flume-*-jar-with-dependencies.jar $HADOOP_HOME/share/hadoop/hdfs/lib/ 2) Edit hdfs-site.xml to include the following: hadoop.trace.spanreceiver.classes org.htrace.impl.FlumeSpanReceiver hadoop.htrace.flume.hostname 127.0.0.1 hadoop.htrace.flume.port 60000 3) Setup flume collector Create flume-conf.properties file. Below is a sample that sets up an hdfs sink. agent.sources = avro-collection-source agent.channels = memoryChannel agent.sinks = loggerSink hdfs-sink # avro source - should match the configurations in hdfs-site.xml agent.sources.avro-collection-source.type = avro agent.sources.avro-collection-source.bind = 127.0.0.1 agent.sources.avro-collection-source.port = 60000 agent.sources.avro-collection-source.channels = memoryChannel #sample hdfs-sink, change to any sink that flume supports agent.sinks.hdfs-sink.type = hdfs agent.sinks.hdfs-sink.hdfs.path = hdfs://127.0.0.1:9000/flume agent.sinks.hdfs-sink.channel = memoryChannel agent.sinks.hdfs-sink.hdfs.fileType = DataStream agent.sinks.hdfs-sink.hdfs.writeFormat = Text agent.sinks.hdfs-sink.hdfs.rollSize = 0 agent.sinks.hdfs-sink.hdfs.rollCount = 10000 agent.sinks.hdfs-sink.hdfs.batchSize = 100 # memory channel agent.channels.memoryChannel.capacity = 10000 agent.channels.memoryChannel.transactionCapacity = 1000 Run flume agent using command "flume-ng agent -c ./conf/ -f ./conf/flume-conf.properties -n agent" incubator-htrace-3.1.0/htrace-flume/pom.xml000066400000000000000000000100371245601110500206320ustar00rootroot00000000000000 4.0.0 htrace-flume jar htrace org.apache.htrace 3.1.0-incubating .. htrace-flume A 'SpanReceiver' implementation that sends spans to Flume collector. http://incubator.apache.org/projects/htrace.html UTF-8 1.5.2 maven-assembly-plugin true org.apache.maven.plugins maven-source-plugin maven-javadoc-plugin maven-compiler-plugin org.apache.maven.plugins maven-gpg-plugin org.apache.rat apache-rat-plugin maven-deploy-plugin maven-assembly-plugin jar-with-dependencies org.apache.htrace htrace-core ${project.version} provided org.apache.htrace htrace-core ${project.version} tests test commons-logging commons-logging provided junit junit test org.apache.flume flume-ng-sdk ${flume.version} org.apache.flume flume-ng-sdk ${flume.version} tests test incubator-htrace-3.1.0/htrace-flume/src/000077500000000000000000000000001245601110500201035ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/main/000077500000000000000000000000001245601110500210275ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/main/java/000077500000000000000000000000001245601110500217505ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/main/java/org/000077500000000000000000000000001245601110500225375ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/main/java/org/apache/000077500000000000000000000000001245601110500237605ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/main/java/org/apache/htrace/000077500000000000000000000000001245601110500252265ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/main/java/org/apache/htrace/impl/000077500000000000000000000000001245601110500261675ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/main/java/org/apache/htrace/impl/FlumeSpanReceiver.java000066400000000000000000000223551245601110500324200ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.flume.Event; import org.apache.flume.FlumeException; import org.apache.flume.api.RpcClient; import org.apache.flume.api.RpcClientFactory; import org.apache.flume.event.EventBuilder; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; public class FlumeSpanReceiver implements SpanReceiver { private static final Log LOG = LogFactory.getLog(FlumeSpanReceiver.class); public static final String NUM_THREADS_KEY = "htrace.flume.num-threads"; public static final int DEFAULT_NUM_THREADS = 1; public static final String FLUME_HOSTNAME_KEY = "htrace.flume.hostname"; public static final String DEFAULT_FLUME_HOSTNAME = "localhost"; public static final String FLUME_PORT_KEY = "htrace.flume.port"; public static final String FLUME_BATCHSIZE_KEY = "htrace.flume.batchsize"; public static final int DEFAULT_FLUME_BATCHSIZE = 100; /** * How long this receiver will try and wait for all threads to shutdown. */ private static final int SHUTDOWN_TIMEOUT = 30; /** * How many errors in a row before we start dropping traces on the floor. */ private static final int MAX_ERRORS = 10; /** * The queue that will get all HTrace spans that are to be sent. */ private final BlockingQueue queue; /** * Boolean used to signal that the threads should end. */ private final AtomicBoolean running = new AtomicBoolean(true); /** * The thread factory used to create new ExecutorService. *

* This will be the same factory for the lifetime of this object so that * no thread names will ever be duplicated. */ private final ThreadFactory tf; //////////////////// /// Variables that will change on each call to configure() /////////////////// private ExecutorService service; private int maxSpanBatchSize; private String flumeHostName; private int flumePort; public FlumeSpanReceiver(HTraceConfiguration conf) { this.queue = new ArrayBlockingQueue(1000); this.tf = new SimpleThreadFactory(); configure(conf); } private class SimpleThreadFactory implements ThreadFactory { final AtomicLong count = new AtomicLong(0); @Override public Thread newThread(Runnable arg0) { String name = String.format("flumeSpanReceiver-%d", count.getAndIncrement()); Thread t = new Thread(arg0, name); t.setDaemon(true); return t; } } private void configure (HTraceConfiguration conf) { // Read configuration int numThreads = conf.getInt(NUM_THREADS_KEY, DEFAULT_NUM_THREADS); this.flumeHostName = conf.get(FLUME_HOSTNAME_KEY, DEFAULT_FLUME_HOSTNAME); this.flumePort = conf.getInt(FLUME_PORT_KEY, 0); if (this.flumePort == 0) { throw new IllegalArgumentException(FLUME_PORT_KEY + " is required in configuration."); } this.maxSpanBatchSize = conf.getInt(FLUME_BATCHSIZE_KEY, DEFAULT_FLUME_BATCHSIZE); // Initialize executors // If there are already threads running tear them down. if (this.service != null) { this.service.shutdownNow(); this.service = null; } this.service = Executors.newFixedThreadPool(numThreads, tf); for (int i = 0; i < numThreads; i++) { this.service.submit(new WriteSpanRunnable()); } } private class WriteSpanRunnable implements Runnable { private RpcClient flumeClient = null; /** * This runnable sends a HTrace span to the Flume. */ @Override public void run() { List dequeuedSpans = new ArrayList(maxSpanBatchSize); long errorCount = 0; while (running.get() || queue.size() > 0) { Span firstSpan = null; try { // Block for up to a second. to try and get a span. // We only block for a little bit in order to notice // if the running value has changed firstSpan = queue.poll(1, TimeUnit.SECONDS); // If the poll was successful then it's possible that there // will be other spans to get. Try and get them. if (firstSpan != null) { // Add the first one that we got dequeuedSpans.add(firstSpan); // Try and get up to 100 queues queue.drainTo(dequeuedSpans, maxSpanBatchSize - 1); } } catch (InterruptedException ie) { // Ignored. } startClient(); if (dequeuedSpans.isEmpty()) { continue; } try { List events = new ArrayList(dequeuedSpans.size()); for (Span span : dequeuedSpans) { // Headers allow Flume to filter Map headers = new HashMap(); headers.put("TraceId", Long.toString(span.getTraceId())); headers.put("SpanId", Long.toString(span.getSpanId())); headers.put("ProcessId", span.getProcessId()); headers.put("Description", span.getDescription()); String body = span.toJson(); Event evt = EventBuilder.withBody(body, Charset.forName("UTF-8"), headers); events.add(evt); } flumeClient.appendBatch(events); // clear the list for the next time through. dequeuedSpans.clear(); // reset the error counter. errorCount = 0; } catch (Exception e) { errorCount += 1; // If there have been ten errors in a row start dropping things. if (errorCount < MAX_ERRORS) { try { queue.addAll(dequeuedSpans); } catch (IllegalStateException ex) { LOG.error("Drop " + dequeuedSpans.size() + " span(s) because writing to HBase failed."); } } closeClient(); try { // Since there was an error sleep just a little bit to try and allow the // HBase some time to recover. Thread.sleep(500); } catch (InterruptedException e1) { // Ignored } } } closeClient(); } /** * Close Flume RPC client */ private void closeClient() { if (flumeClient != null) { try { flumeClient.close(); } catch (FlumeException ex) { LOG.warn("Error while trying to close Flume Rpc Client.", ex); } finally { flumeClient = null; } } } /** * Create / reconnect Flume RPC client */ private void startClient() { // If current client is inactive, close it if (flumeClient != null && !flumeClient.isActive()) { flumeClient.close(); flumeClient = null; } // Create client if needed if (flumeClient == null) { try { flumeClient = RpcClientFactory.getDefaultInstance(flumeHostName, flumePort, maxSpanBatchSize); } catch (FlumeException e) { LOG.warn("Failed to create Flume RPC Client. " + e.getMessage()); } } } } /** * Close the receiver. *

* This tries to shutdown thread pool. * * @throws IOException */ @Override public void close() throws IOException { running.set(false); service.shutdown(); try { if (!service.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) { LOG.error("Was not able to process all remaining spans upon closing in: " + SHUTDOWN_TIMEOUT + " " + TimeUnit.SECONDS + ". Left Spans could be dropped."); } } catch (InterruptedException e1) { LOG.warn("Thread interrupted when terminating executor.", e1); } } @Override public void receiveSpan(Span span) { if (running.get()) { try { this.queue.add(span); } catch (IllegalStateException e) { LOG.error("Error trying to append span (" + span.getDescription() + ") to the queue. Blocking Queue was full."); } } } } incubator-htrace-3.1.0/htrace-flume/src/test/000077500000000000000000000000001245601110500210625ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/test/java/000077500000000000000000000000001245601110500220035ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/test/java/org/000077500000000000000000000000001245601110500225725ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/test/java/org/apache/000077500000000000000000000000001245601110500240135ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/test/java/org/apache/htrace/000077500000000000000000000000001245601110500252615ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/test/java/org/apache/htrace/impl/000077500000000000000000000000001245601110500262225ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-flume/src/test/java/org/apache/htrace/impl/TestFlumeSpanReceiver.java000066400000000000000000000131151245601110500333050ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import junit.framework.Assert; import org.apache.avro.AvroRemoteException; import org.apache.avro.ipc.Server; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.flume.EventDeliveryException; import org.apache.flume.FlumeException; import org.apache.flume.api.RpcTestUtils; import org.apache.flume.source.avro.AvroFlumeEvent; import org.apache.flume.source.avro.AvroSourceProtocol; import org.apache.flume.source.avro.Status; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import org.apache.htrace.Trace; import org.apache.htrace.TraceCreator; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; public class TestFlumeSpanReceiver { private static final Log LOG = LogFactory.getLog(TestFlumeSpanReceiver.class); private static final String ROOT_SPAN_DESC = "ROOT"; private SpanReceiver spanReceiver; private Server flumeServer; private TraceCreator traceCreator; @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } @Test public void testSimpleTraces() throws FlumeException, EventDeliveryException, IOException { AvroHandler avroHandler = null; List spans = null; try { avroHandler = new AvroHandler(); startReceiver(null, avroHandler); spans = new ArrayList(); Span rootSpan = new MilliSpan(ROOT_SPAN_DESC, 1, Span.ROOT_SPAN_ID, 100, "test"); Span innerOne = rootSpan.child("Some good work"); Span innerTwo = innerOne.child("Some more good work"); innerTwo.stop(); spans.add(innerTwo); innerOne.stop(); spans.add(innerOne); rootSpan.addKVAnnotation("foo".getBytes(), "bar".getBytes()); rootSpan.addTimelineAnnotation("timeline"); rootSpan.stop(); spans.add(rootSpan); } finally { stopReceiver(); } List events = avroHandler.getAllEvents(); Assert.assertEquals(spans.size(), events.size()); for (int i = 0; i < spans.size(); i ++) { String json = new String(events.get(i).getBody().array(), Charset.forName("UTF-8")); Assert.assertTrue(json.contains(spans.get(i).getDescription())); } } @Test public void testConcurrency() throws FlumeException, EventDeliveryException, IOException { try { Map extraConf = new HashMap(); extraConf.put(FlumeSpanReceiver.NUM_THREADS_KEY, "5"); startReceiver(extraConf, new RpcTestUtils.OKAvroHandler()); traceCreator.createThreadedTrace(); } finally { stopReceiver(); } } @Test public void testResilience() throws FlumeException, EventDeliveryException, IOException { try { startReceiver(null, new RpcTestUtils.FailedAvroHandler()); traceCreator.createThreadedTrace(); } finally { stopReceiver(); } } private void startReceiver(Map extraConf, AvroSourceProtocol avroHandler) { // Start Flume server Assert.assertNull(flumeServer); flumeServer = RpcTestUtils.startServer(avroHandler); // Create and configure span receiver Map conf = new HashMap(); conf.put(FlumeSpanReceiver.FLUME_HOSTNAME_KEY, "127.0.0.1"); conf.put(FlumeSpanReceiver.FLUME_PORT_KEY, Integer.toString(flumeServer.getPort())); if (extraConf != null) { conf.putAll(extraConf); } spanReceiver = new FlumeSpanReceiver(HTraceConfiguration.fromMap(conf)); // Create trace creator, it will register our receiver traceCreator = new TraceCreator(spanReceiver); } private void stopReceiver() throws IOException { // Close span receiver if (spanReceiver != null) { Trace.removeReceiver(spanReceiver); spanReceiver.close(); spanReceiver = null; } // Close Flume server if (flumeServer != null) { RpcTestUtils.stopServer(flumeServer); flumeServer = null; } } private static class AvroHandler implements AvroSourceProtocol { private ArrayList all_events = new ArrayList(); public List getAllEvents() { return new ArrayList(all_events); } @Override public Status append(AvroFlumeEvent event) throws AvroRemoteException { all_events.add(event); return Status.OK; } @Override public Status appendBatch(List events) throws AvroRemoteException { all_events.addAll(events); return Status.OK; } } } incubator-htrace-3.1.0/htrace-hbase/000077500000000000000000000000001245601110500172665ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/README.md000066400000000000000000000127571245601110500205610ustar00rootroot00000000000000 htrace-hbase ============ htrace-hbase provides the span receiver which sends tracing spans to HBase and a viewer which retrieves spans from HBase and displays them graphically. Tutorial -------- In the example below, we use the same HBase instance running in standalone-mode as both tracee and storage for the tracing spans. First, get HBase and build it: $ git clone https://github.com/apache/hbase $ cd hbase $ mvn package -DskipTests Build htrace-hbase (by building all of htrace... just takes a second): $ git clone git@github.com:cloudera/htrace.git $ cd htrace.git $ mvn install This will add the htrace jars including htrace-hbase to your local maven repository. Add a configuration that sets HBase as span receiver in hbase-site.xml: hbase.trace.spanreceiver.classes org.apache.htrace.impl.HBaseSpanReceiver Starting HBase server in standalone-mode with htrace-hbase jar added to the CLASSPATH (use appropriate 'version' -- below we are using 3.0.4). $ HBASE_CLASSPATH=$HOME/.m2/repository/org/apache/htrace/htrace-hbase/3.0.4/htrace-hbase-3.0.4.jar $HBASE_HOME/bin/hbase master start Running HBase shell from another terminal, add the table in which tracing spans are stored. By default it uses the table named "htrace" with two column families "s" and "i" by default: hbase(main):001:0> create 'htrace', 's', 'i' Run some tracing from hbase shell (Make sure htrace is on the CLASSPATH when you start the shell): $ HBASE_CLASSPATH=$HOME/.m2/repository/org/apache/htrace/htrace-hbase/3.0.4/htrace-hbase-3.0.4.jar ./bin/hbase shell hbase(main):002:0> trace 'start'; create 't1', 'f'; trace 'stop' ... hbase(main):003:0> trace 'start'; put 't1', 'r1', 'f:c1', 'value'; trace 'stop' ... Running the main class of receiver also generate a simple, artificial trace for test: $ bin/hbase org.apache.htrace.impl.HBaseSpanReceiver Starting viewer process which listens 0.0.0.0:16900 by default.: $ HBASE_CLASSPATH=$HOME/.m2/repository/org/apache/htrace/htrace-hbase/3.0.4/htrace-hbase-3.0.4.jar ./bin/hbase org.apache.htrace.viewer.HBaseSpanViewerServer Accessing http://host:16900/ with Web browser shows you list of traces like below.: ![list of traces](traces.png "traces list") Clicking the trace in the list shows you the spans.: ![visualization of spans](spans.png "spans view") Light blue rectangles represent spans. The horizontal position of the rectangle represents relative time. The width of a rectangle and the number at its lower left corner is the time from start to stop of the span in milliseconds. If you hover over any small red rectangle, you will see the annotation associated with the span in a popup window. ![timeline annotations](timelines.png "timeline annotations") Leading numbers are time of annotation relative to start of the trace. Receiver Configuration ---------------------- Configurations for span receiver running in HBase to connect to the HBase to which spans are sent. These are different from the properties of usual HBase client: hbase.htrace.hbase.collector-quorum 127.0.0.1 hbase.htrace.hbase.zookeeper.property.clientPort 2181 hbase.htrace.hbase.zookeeper.znode.parent /hbase You can specify the name of table and column families for storing tracing spans by configurations shown below.: hbase.htrace.hbase.table htrace hbase.htrace.hbase.columnfamily s hbase.htrace.hbase.indexfamily i Notice that these configurations are prefixed by `hbase.` because the tracee are assumed to be HBase here. Viewer Configuration -------------------- You can set listen address of span viewer server by `htrace.viewer.http.address`. In addition, span viewer server uses - usual HBase client configuration to connect to HBase and - receiver's configuration properties without prefix to specify the name of table and column families. ``` $ bin/hbase org.apache.htrace.viewer.HBaseSpanViewerServer \ -Dhtrace.viewer.http.address=0.0.0.0:16900 \ -Dhbase.zookeeper.quorum=127.0.0.1 \ -Dhbase.zookeeper.znode.parent=/hbase \ -Dhtrace.hbase.table=htrace \ -Dhtrace.hbase.columnfamily=s \ -Dhtrace.hbase.indexfamily=i ``` Todo ---- - enabling to focus in/out specific spans in trace. - limiting the traces shown in list based on time period. - adding utility shell script. - adding tests. incubator-htrace-3.1.0/htrace-hbase/pom.xml000066400000000000000000000150301245601110500206020ustar00rootroot00000000000000 4.0.0 htrace-hbase jar htrace org.apache.htrace 3.1.0-incubating .. htrace-hbase htrace-hbase is the tools to send tracing information to an HBase database for analysis later. http://incubator.apache.org/projects/htrace.html UTF-8 0.99.2 2.4.0 2.5.0 ${basedir}/src/main webapps/** maven-assembly-plugin true org.apache.rat apache-rat-plugin **/generated/** **/webapps/static/d3.min.js org.apache.maven.plugins maven-source-plugin maven-assembly-plugin jar-with-dependencies maven-compiler-plugin maven-javadoc-plugin org.apache.maven.plugins maven-gpg-plugin maven-deploy-plugin org.apache.htrace htrace-core ${project.version} provided org.apache.htrace htrace-core ${project.version} tests test com.google.protobuf protobuf-java ${protobuf.version} provided commons-logging commons-logging provided com.google.guava guava provided junit junit test org.apache.hbase hbase-client ${hbase.version} org.apache.htrace htrace-core org.apache.hbase hbase-testing-util ${hbase.version} test compile-protobuf compile-protobuf org.apache.hadoop hadoop-maven-plugins ${hadoop.version} ${protobuf.version} ${protoc.path} compile-protoc generate-sources protoc ${basedir}/src/main/protobuf ${basedir}/src/main/protobuf Span.proto ${basedir}/src/main/java/ incubator-htrace-3.1.0/htrace-hbase/spans.png000066400000000000000000003166401245601110500211320ustar00rootroot00000000000000PNG  IHDRz@&iCCPICC Profilehy4Um31<nng H`p077ekv9+9;3#ۡX#4p$sG =] +>G=眰ԂDŻK΃ */Bnqᠠ(b~_:p@Op?pS^y.Aн;^^'fB@ D Cn{VHp?SSf7fG-5v,n t˓g T> ?G+ @ pAW/$,P@3p؃е 躣@,Hi \WA( 3tW `Ly؅`c`0y*Lf \a>`X$, ˆ`FX 6 [#x8煋p# 3s2=Sx |>_o"A@ Z38B#&D7b1XF Hj$;RGZ#=as"d) 9F!Pd(fJeCPi|T5GmhZ4ZGϢϣowY&aaT0f7)L 3ƒbٰX]6Vc[߰$E3O3$$IHHIvq8> +^&p뤤 ~ H{HIwTxA Wddddddr $&&%7 $'/&J|B$E E>ce Ep## MJjJ J3 Ք T*^**OrTj.j-jd/h"рO&'hhilhiiZhhhGhбiyeҽMDNEE_G?LA!3όHFAF (ƛ/LJLLYLƘ̖̂g˙7YXYXBY`YfeUggʺFͦv;; { {!{3>G$G)G?.'5ggg.<7N5n6nX1y_n߼|x bj&?n e}BB~B7 ˄GE""EjDEiEEDq9];->.A%a($$KRPCXTTOi!i/eeLde:eedeke\ˍ(4+(*R|$Ţ|[yVSMTeJ]UZڌ:z7  {+ڵzY:T::E:>5kz2zgQFG X < v፬fÍL&&M&LyLM3f̛-_-%,c-\Nh=1noiiCads淭m픝]{F{?CæUy'4g>hޓ'OPe82:83btcE8;Wzv\g>--/G.zv;w+++++,ݽ[\[YtoZ:ںA]<2zXq'볞žyT}ûF&fϋ[hZr[q)m1m>./^|im=*={{_˿~F>2oe 4 * 6S~^}ǐЫ 84:§O?N'L&>>O2O}R7%;2=7c53>1417k7ow$/.~w>'}kvk?:ΰ^!ѹi9;kajG~oQ{}àPp\}½U =ԃPNAWv<  A`qU*f4t! |Xpq~s*=!V+~ i.U =!*"MaH Z֥I[צ?acDc,fojm~eջl)x,} O>pym9OߘiW _BPuPrhmXx\aDHQ,Qg^Ԝ~8^.+x#sJj[ڃ̬s}/8X\T$'t U|DNJܵOE;nl*i\RY}Hŗʅ5$hs֊)o|gxo=j:><07*8:1Oc)i>OM^eyƴ ry6bNl|׈o `{1q+43k~2]g[ѵY[{i{sg콀}CCSfH-+: sc!ħ}"SR}"ޡe` aǼ*^ϱ%s+?E‡Rb%ydldj?*•-UbUzW4ZrN[QRo$jlnnZ`dn{:ܦжn(duU'mMYnB@(1t/l:3TRi(ڨ3e1gΚ `Ȟԝ\F=5roj61{ 7rNZ\Dzi1+)W= ;Ut8 "%[Me%ɷ}VHW2TowՔ˸^T@!#3O[vB㹦f-mRB\/躨^R"&^%S ҿc|2s{g#'1q Ϭ _ӈ?33s_{P=srЏ+*k?~~mج}jfGퟍ݁vxB]1oHq٤d]"e Q& U͇"G +a?),xF(U8[hXxDdTt)Y?9'yUEQ%eR-Y~Fr󚧴uuDtiu4Gx)g,,XޟHI`ci,<}ٕumԽݣƳ+;'7==#4tSԫ3_b݈?'P&)T\fI' ; s,r̕ZX3A(l6[vp8N gs9 p{? x>^owG!{߀ *3!PB"?!b< ]D;1XE!H"2hE BEf "ˑ>rBP(1* @Š2Q*3T7j AA-?]nzAc1e)]iżCKǡ 56"DĒć$$wuʼnp0\:&7%&$$u '"-#m"}OG2xS> ߇ѓIy%=!'[$G+[g&o#'ߢЧ𤈧(xF1DJ %tD-B;aFECKMYG9DMJM@GH5CvΠ~D=I$!݉ >MM-V֗N΃.n^ޓ[8C C)(#Q1qɂ)i2c7,HEȊ+X&XXYϱ>f]`cadKgkf[ebefoc_pcSӃ-K+k[;{ǜ'gWוŧW7oο- .+pK ``P'a*a#T6) JQfQ[K}b1MsbbVJK8IJ KRJJfKHZv7d$eddVdEde. - ߓ @᧢dOڔ:oTU,UUTYUU+T"՚ԁzFWMaxikijehkKuttjfJG7] C+F2Fg:I͍ ԛjf1y՘+' Z8YܱX챢rmrBD74.w7lTm2m>ز c{hjvg$:3;;7Ğ=YqrEWWYt׏nn1n},!D&O2O7z//gGo'G>X>O|I}}(:x>J~ * :v n W<47t%46"<4]TD~)Sm\˧-O7DFF-G~~LΙ11}gϖR.ƽ:'k߄DėIIɢwSxRRSKҹӫ2D2g*fvfede8s{ /! wb%kyby//;_޼sjg3_-*RD^tؤxz qa#KKo"JL~V={'Bb2nD5cug={]kuu6u<4~c_}F|c]Ez2GZ"[~gvvtQ%52嫺n垬^ޞ>ooi;Mp x7>qc0||Dkdn4#W|ưcU'? ~;˃)_ӗgggO=ZMB"bwK7U'[a]i]u^_S:6l767lIn oWIe}g@(_#E#1G\g1|@PZo 1 @a@!fľu!M X#go?Ѕ`ia0NLbLwE Eb` tWaaأv1Vaap Ng;fT6[^`x< σ_߁>ȿL`A#$*}%8*W{Db1X)<Ƀ@" Hv6Y|@#'ߑ(4D:Jwvj5)h C'.0+7aGlvńa1W1FLfbJXS6-a;#t*ܦ$$Q$Inԓ&B#q8\$.W{yCJ %U!"'MjuH'I7dxn2>zOFC&JGBMv39\\܉4Ej.I cFSQBu H&]/]J:J)Js@L;_(d¨rQZFSsSkRQSߤn%2b8FCDLLsfIUhsh~MDJNFWM7@A@JAy\ed0`e(dhcH(Ƙq $Ȕi,| E%eUՙ5sqY5-[7rpssrtq9EƥUۅ=G'gW7wϙoo_/`()#L e &6)eu- &,*V/#*,#A.a%qM$dc)u i:+222=Y{22rz+R()))M* (G*wثQ:Ʃ֬UV/S_PьТ:uOkWPNΨ.nn^>NQ-_چFJF9Fc&"&&æqxb͹̣ZpYD[[rYⵊUD‰QkQT66mlm.ݰ۲7r98: ]w6l}v9pdVciKbxd=!$[8B a<(FT!B9{؇2FRm"i|OQwP8J" JEQQ7X4Z :Jsſw1 /F ca.c1Q eJcس{.g& 9d$$$H*I:HIpN熋qIPZԑ4 C~ȻIxm;d7c2:2Y2kk}1{_ayȇ)26Q)) !PG&QrSPFQRACeIHUGZ:NqDUb8IC1IiE+DI{vΘ.n^>!o2/LvW13Bd:`Vdd~ȼR2Ċgf;;5[[ ;'5{:{#2+9GG=7NNcs9ghbs}=Cs/W7T%S qǯ_?*P-Q/&!X)8.D!%%T#E(/+PHHȊ(h 111O"Aqx]) : STBEpRR1R ep2Z2q2d~ @,G/wB\QU~WAAuE P:%Q Ze1P*2*Q**{jɪjjjWսkjii$4Ӽ9ũUݣCu 6]gЯ_7P4H2xmHe`XfH .cMo&&gL:M֦%fRfqfkJi,-}-[ZY[͞;qDdnu{666Rvvv8{;;*:f;N8@Ι9ҹ+lw!4\=]<)ܽܟ{Py{tx2xyzqz-=u }}|k0~_(l61CBzCEB/n9uoExuJ ##GOkbJڈva71&q7\22| mJyd4IL2Odʺ-| 9gryr_L$~i:e˻W^g)-4ZS,[~7J*nyrN,wx{Ε Jʞ仪wW?vo~VJZ]=} {\zէ2O4`Jlf7yre5uͪ]ja_Pjg ^,tYuB x5ҭ}'gש775y{~_Aw^x};14 u| go1'Oh-'8'&~}1?;KTƴt LҬ9蹱y_W8%}^P_(Y_t\lN=Rz?J~^1[X[\\]3_+_/_ Gܠ8qwccSu3}spn֝~G~{g[i;vNΓ?K`wnn`/fz>f_zu?{~} |`yuPtr0ypprthwqxppR5^:/</C >l4뿎ׂ G/?±iTXtXML:com.adobe.xmp 1053 536 G@IDATxp#yټ#c,dsQg++;eg̞+ȋr藲DX 2@us?.6':EDZ\XWz3 vI-%W_M~O!$@H $q q1*@H $@H@@H $@Jk%@H $@@H $@Jk%@H $@@H $@Jk%@H $@@H $@Jk%@H $evIQ;?DxA]W_xaSS_Ї^OӤÅr7Nᐳs)5*/@8 &d aP׽κe)2H(ݎRPZJUvfxN|*MQIpqG ̒'@H }!c1?lh08&1T'񍣆 tP8AOaQC#:reGvE`+3DUc |kOl3A/%n DSNĊ$cATܦ #/3V>ef*fݤjky lx, $k̶hbgK5 f6- 0o>=Ch({N@H \ 3?1f0(>;}U H6nmmbp~[kHvӃHJZyZ2Uw7!Ii0Bp#EߡUġ#n+5`ee7ۚ`E-2m˴J' *S#uLx fs{3 >>TkA\~NU-fb̞۠AnmZ4EEILkݖM3d@;RTiUh-sTk_dFb}7냾_YDH $ppc k};_VH|tkm6)w |BC>+H}jf<0Zt@_}(ٲ Pc[P1P0HD ݮhd|>K*3U)oiyCrzʂx”7R EM.ZJb}$.*U<2әSʇ Ms RP==ƨ谒I֘)Y %f `DH $p0 F^tJ%|gL-h-clqo`&+e2B-(f-Lΰ\n+ }._"jps[)xfWUA,!$F8f03f-~Q_w̵ZmX-" RlkAxJ]C6]c[4dh 0I"6Kؽ]S5GdLG:l ;>Y}Ƹg]P Xk&s `F.|+Qh|I#vGH !ct)<@˾0dml,a +bxR ]b<m/ @ 8i7Z|XC`"\$4@e;]-ì$:.)pԉ^.3r3>9}v#m^+!iJCWJ)D!d\mBc.vB@\(]Zpp.w  u_x’_]R*&8.i~S2NWkKșGrxkJF֯A7!Yk$@ t1f :đǟ 榤hixk'o]H[Z!lk@*\\_$S҅0P:g)I1 hr! x9S \ݨTZY'>(JtB b@pq;^=N"12-{G0`:,WZ7VZ7BqeO2hr2UVJ弓ኙ"nHWV'''J)* :^ZG] S |v6Â;^b6y9T렘O6m>5Q_jM@H 83_018)'({]ۿN'~b 7gxa旅Xػ1t ^ 1ر$ P>t?`ƍ!Pجmlȶڛ4á,CA$@J  o 1GM8)j0`4齜3;< \fDE9ۂu`$,&х=DޖUsUFG::݅w~RH $@`ض`3(oϱGEѮÐ@H $ ܷZ(@H $(hWaH $@H {H $@H "v(*@H $^n/(n|7~!H $5SU|DH $@H`Ю32@H $|DH $@H`pb0@H $@CЮH $@H {F@H $"vDH $@H`v ]m*="E- ]U3&D;"ЋBY;z_zܥۧ/}eozkޫAi6.W\,u**qiJSqE@T;nCH $yPzS $ٍ{ez3xZS3hћņ'0H }H'=#:/Rs7 ?>E}O[7 O͉1|׽|rnFxȅ ԓoi[Pr\ mZNo m^$ɹL>tH $80\%K5ݦRɱ+ ;h9li 5~bPӯ `>ܵ\&d-ZP*j^lFr;I[klb0aG|66=@H +إ]anL?ή )QYN55utҩxYq9Z`Ѓtn:A~ݿCbʪ,:.Q5KFx2Z!i6šQO⓼.ՔO$A\ZfMނZ7B6+%3*M-tr9"+3UW 0*uŃ@1[_9.)\L _|^y齗_'l+n'Sg:|ZH{5izvȴK|IZ;svILeܔ7 1=) b%Ek0MEԫ%O͜UT>uƿ ?@H $pvoiyҪuR͑`^MN4*tUߥ.|_)RSefX>Rz]vWt:e+0^gae>avI$eYr v6t!Rn. HSgK|nWxYD/It5s;Z:D"f99\Rj2H $8${+t"8!g*jTv*Hw5Yϥ Cu$IAü_wY]~k^t7)NrNz!WזV*0.)F̩%⋥:v` Dҡ•v]\hʹ^GT-[^)lvk2z%tHHPhB9-!$@H d) KP'΁IeFma Eכ;om/ui ;5WQPOFE""}-\TJŹssfOdy'jpO<)z'`IưA dXZn`F?@H $ _,N* ]x*dG :@{0ćz*# 67}tZ|YQo \'g`v?5 N.sJevn1HfDu}#@ORD95&(깤lMsD$ BH $m+c_lkZ Pp(5(kYAǖ]mW:jˍGGI$p8\b W'<+'`26CafO64.!fGH $:h TH SSi)989)7w,3zk,|xwwv@H $pMv2HЕ̳!;cQL&KɏL82ʢ"H $86{}IlV7s` {Y< ]LJ $@H`pb0& KWdXpS4fm#$@H`|>dۼ$ҽV ozD@H $*|ūQn$*'Ym%׍T*, @H $W2p[*8W'> L0/>*H $8VǪ,@H $@B`_AJS!Nx#7SLWNW ˠ ]ɯ~7Rl6Uur{%Z7 TR+qVn {kvӝZH $;!ēiSZ(RC.ٵ U2{rZ;{#ԕ=F1um_H $}_!9S:\W{if_Tr,X>®OK,wx`ߗ+5سαʽ]KN`MXyBRlh4ZCӋ{L|K%!b1JϖսTV_3\{lhٳuZVxU@H /bW"_s-wJgX4)QYd{g%9ZSyxq՚,Nm k$ƶ[Y'&r80JV$/q\T2Z7*QטC[n*4{%1]SMBTӾFR,%ZuSPMuji9^hrf/TWG+MhR*FYx=`"<@H 0y0ITZtZ{Rz v7G <;/Z)&fs__*_.S>zu3AC|9$6Rȍ"T 2U&Je`!C+Oe2p(:$p`Tdi.BmNkA]!BlneYUEVkViR<T]5 z'#/o*CheGA(!m rǑiw r18Tl#@­`>Wyԥ X )I$0sW |h.˗mY3-BD40 ۰|'.SahYhl߅7~ $8N>(B7qǿȷ+K\~O6 q]RVc{ c$pj( 0&3_ Fm* ̵蠎D` Ӯ(Y|ܡV6 :l=U̶6_$Ub̈́ZQz yKܢC[C6m56IB`6Bò+6i\JVnW\ȄܵM(ORC_AMڻ)e$x<|DO@ G!CvQBf.U6F 5՘]=dvYn B$՚G!$8f<(sX4/ҟft0ufRY'rFe|Ī~'҂;הf=JKk)8˳9tjrt.Jzs遗 CVUWpmHp!sZ5VZ;-Hr)G{Ui6Kٕ\[h[{چжk^T6pOd9W&w֒k$p >;u9Rُ? qg G47%m4sjbp+s#KJ[ +S|]R3&/[F8F6H6n9-?{_t[NU GAeIBn)ּS'YCH $p\ ]cd].A_.;`SҔuy []D ^:,t-?m+JiuqnU5w، #k.(0!xh >$p \gl--n* #ރ۰ w.dp~eI^%򋢓+IB53fRr] 8PD3} d_ +Riqq'ٌxnD/E'gWh ċ^$}m^X8GRխ04>^p&8?tJ=bd $&A؎à'8>FR+GË́2n1f= e2TȓjD ; v8VS`$tCJ d«UyT1FRAuJcY'9q[!հm> Ð@H aGɮ8˜P5$BxZ(Y[w4] PO̜#LQ:$@GGB ^zE^^C>#ST(/L/mD%UQ$@W'v8,h8WJ|N]u $@Б& Nj. *@H }%vžnh xw{nb@H $'hW  N/9WQ2\p~ #$@HF  "+pɉYIxݕ"=$@H pb}n}ODH $1%/v4t€6-9#bUQzp 1 ~ֳ;_|W. ?r]~yUyŋ?M'n1kg/^otȥy/LN|gxyفek;-l}q4u.nX@H ]Aߜ&Fs^pBC다)MNoƽ{3xZSo5մ?UCx+}OBm?L]WNEK-6WZ.ybnOõ8]zrL:znbrnT zaXRFōJÐ@H #aL \jPXwvc?A/mliH_ߴ?wߵ'.={_K0*Mf.+~"?k} |~fчWrBK0Eꑅ~_? U&L[Y7]YO}aC^|Ъ<~羔t`{K9w>-W෨}uFl<Ϭ}${Fqr*~4HiGSќ!*Kb=PkiYB6%)^m:,DWk>p$4Xϥoe/-7ZC6z@H f ]3u,#d#]QyT'_zJ'/)2(@zR:"g|98^)8DMw쒘泉)o\_:35=I\CLH_x?wY]~8k$!/}c/Μ<`#ߕO'><ś~!|`( o}z;᥵=k?|3?~/&O/>h>Ѐ23lQSg>k)[}/=>ݧQO5^7r*"+Kp}|[KS <2eOru|9TG6^suBG/Wɱ0SPt%={j T>xaӇ{Gw8޹%WQomq<Ta0RC.z@H n_  K3'b8>[Z0rs$Dީ_ >KSiHRW+'!2?^w81NW2҅H +wO>OfS?w!Mw3 ~执/)dKO+]_a84j6139+uVa*uV!I}e}u>t $[09dS!n%'\Hsrje9ԍpH $^ǮGXdԨ+3M +)ㄜQ٩,#I*5Yϥs ioq+Ͻ>k ߅zfo=%/]04—GG.ĉ^.^{6aM'Of@{Yrd'%<+O_:A~J7.nPgK poMϼt~ 2W|m[޻@G|\~;SH/uTFT`Mhs8$^뵥FFJ.ct;. x'0Z-1 $^sǮlp:M)!JS+ėTS\WS$ -?m+JiuqnU5i@!${уmv!x._"7]M䢙g"!SwG~Joz7xg~0_y97#pS3L)qkk [2x iI<*9=K^_$p ^xo>M> \ayn[/MqDVo~AP38  5՝Y)ŧfiE ?j󅼢/肁˼?0è`~AWZ K5@H $}+F_,N*X0aԐoktT}z-Wy9jeK.IX`7O9'aP"C0a}waF⷟{7;: ?ũO.VϾ.y(ynsc0 FSDԞcp@"-B̩{~tq-౛/oY~5yr_ o&ʋ[YA6JFN h &kbįh}dqڛ)U)s疈Òڙ 'p=e;wf߾x'M_/]}=?$]4eM |ZzGE^ ~ew-rwo>ViSk7.-MS}YX"}/h&DE80}g K/b.=DZ~縔/_Qg,o}0 OrEW#|•ZvJ-/Á \|oPtz2."gbGm&3k^r[Q%$@YkwZ+k-{JZ+a-vW+GtD2n1-d'w v v"*)VSlG'K/Vj V/τ 8X+#cxwuSq/x^2p-}+O~rK|/,.}^Spw 췟\%w%x4\YSI3)Aw=A~a{ˋE>q7/2͇d>wS<_"-߆"[4'f튝3+n*Zb]O~;ھ'ӂZ唥'm;]TvG Vc7X _x7JC3YDH $&۶~̯ѣ& Xh@R/1YW ]xutero>/=ӹz*\+nbk._a1;fQY%xgʼnR6Ey+gaʎa ϖ*e,M| kDF#a{QXWWHv{=@H ]q#sƲkz)ꝭA66Hd?9%q΋+5}RW+)L $8ToP̐fLI4"2/B@H $+7ajizɿՇ:yf:aQ5$@H + 4fs VOfZDԩIV(?uP $@DPϙ&M12faNH3Лs=`w복f@H O+wz%vie =BT(3$@H F ]{%Sz.U&'h"ӛx^<@H $pCsfo s{V9O $@G!T=x tn֪S_oweЏOƋȿx/~qvRGHQ*h?mh (}Gvp._JSwlHEwtC@H \oWMqrdy*NN-4H!nkj'g`ICk{Ziؕ\{f$* |_?~m+#FZTz k m~tss#4o JiԶ Tѷ ^cGtT8 $!% q C`BXb[Zٟ~* n'襍=1?Ѹ붳!r6<ZbpuR.َ ̄QBwA9}wT4-8ű#:o3@H #G Vqtg]tJg؅9)QYN5*@]~r„Z!ehNaAj-)'+J$OL9=H`|O9Kg 豺 3.KjͪxjܨaZ tpQbAXTKrz`+-L' Q744͗H"n#N}X*[* lxR~K_jdz0x~^B'Fq5:_UVnWO('MZ5$W˼^oJ"|>$zkFjz0׆XAJ4<$@ǞaUxbŒm_4逄9?Nș9bܹ4tVZZuNyXșSKP,sQk0tX9{tJ<+@@:tmUz Tg?ȿ曈@zWk9wh] ? ,U)5}Q*L̓ 1SvX$+ԣ^RYCr :x<̪aIUP>פf mCj8_^yޙz@IDATn,褥u)6&?Bse 3U Cl̀J0k0VRMZ{R(\'*|TK:38zZbRa.ݹ#V6ET&nYڀ$r2;pW#diR?g_ !$!]YeuWˎ#d) KÈJ5J|r"@uY[.R Wj9vk| ^s@T ~" pҴa<{/E!+.!?8Al86"Pno. H9SPF0 Iax0эj.\WJS Idբsfi؅@^/^k4=" HVka᜼*_4$n0RdWe!Yt# c{삢|lzG$}-\TJŹssP@/@H ϸN|1πn1F iUyst 6SXdؚk*.C `7:(]`V6 aR=H`_alUZ _Bu7l˶7tuM*Ԁ%N!< {ZTٴ%e۰ط@S:(c]ae $khyNo|]e-([SD|kmHݓ2fl"[mWz%ޭX#kfLMp=I0OEA#FBY;f1+c $1 r?슾IaU7,nW`u]ǘHps 0I Q,vl6dxR֎1e4QPaoۗ}AH;0ƿ{n0|Gm256(:j1^#}1w #$E0 BZMvطm˟&Ll cl@ Ln#h=LJlHVj MEgfFC $9C%EssEH $,g2zQ"wN{7|?bQRuAH $uPSz+IitՍ~1#$@HuPX#עqn%.A@H cL+񗇪_OB.䢓9z*y#$@Hz@H $'pt36-B}="0y~ꪢv##GK?}۷|پ5#4uhai;ԝ1ZcT:;n )  C7%{UbRZpз&cn $D5XK7f)]c_➲EAV5*@] r„Z!eh(͒mi=j orp. 7zFWk^E9^:.aUaQ^(Pt]-IlnFEٙ2mr4ӴQ(UHPZlQtۘYDxr&lԢN %j5} (0ɞ5j!X2, u5)U .4;f{(%F] pev櫫i{e:&B].Q;2 Z;dR'@H MMV`&]k: E|-X]2Gmւ|J1~7k1//)  $v@nphdBl>",Ei u_jdz0 PVJE+/Ot*zB|>*JGc VrVW}YbP|IGmzЗ۪BT<XLu/)W˙m7Y6TӶA[42qC41UƄ3=}H2ޓ`R4-ߓʰd|,@T }ˀx|yc t)/HAgֽ- E Q]p5J@H m賺Qr"jA?8:L ڰ°= b00)[ކч1a#HRk4A:jP -eW@ex֨-G ֢l$kVrfN36|.`8F6fژ "f9ulwp +#Ӯ6Kk0<.2Y ƧqL`QfMb~>>a2# #KnfDڞn@ xF1qGm KjGWlX :$@Gy^ OXt0u9$rFe|Ī~';הf=JKk)8/9tjrt.Jׇ:,} X{HU}ရ CCtZ{ ҄m?NX+pCZ)s̫͟`mH+IBbP3dxPDeuP;#Sֽ4f6n$s zB3t/ ;Od$}zt#Zzzn&.#wTu-̭̣yu捄z.0kBg*\FTn4 >Oys}b)Q .9B ˱\PQFue4厕8b@H E0 (1#r:+e_ ;%+MIl_#y_WS$yf~ qVRVf_[3f\x+{њ_vX!6 H 3)o䉆%R3C_ EὒЍ \ `.j.vQ38<ρm*=Q),*,mLL\.{>,#[?*qQ99*V Sux0&2.uLT f,D }He((Ğn h_0+i72"@H B슎~ m ŠueG qE\9V&OQ:C ~1B9d!B! `U`H[pXt^zZO"ϳK*ND*"0PO<]ht ϧp)IWp3*tvNhfQSoϑPQhބq m'R2 cו3b[ucL., B)Lʷww`b^JlQ/$4!^ia7׼W۠s~",q)@0MBIT79 +lЃ^؃]qLwg&H $2_V9[{LyvMXlmo78ܒa۸IvX<] 57tj6hx޲Z a&eTƓڭ|G\2~E ^}۰5[\Z|+B2s *ewNOln7` p0UlZL.%8kȔvb*CiUY F(V" D˨ķʴAsTղr NY/f(gC7CLDu v0*`1N6Qt؀R4j ]?.p Sq6S4(n1:_/VҷTpa=)lo 'ˮ΃C[jK;-TgfXˇZUxJ͍Рs7C٦2;`p<*Zm Bod=!T+k!$8&@9'H{`9]@ P/1`Q"3&*#]Ur;_V q~[ TJln#1£5ۅ0ј AۭQ"E=yťEWɩy`KЛ^˿j[B uYEMO20z@H  =GCQͻQ U!}!ҧfZ~măHGbmB&bT%=Ƹƅom^ gXugtS$eQK=|6X6vBH $pXQ$o1)|&&j`uNJvT|L)7kN@H $p8>nKv JMќ_]:eF@H $0DR/Q! ^xၻW;*H $8tБc7$v Y2,@H $vCPB$lnQ $@7+n t8W/@H $'ܷ}=cH $@H pu=զE@G#)=}g]Hxǧyev­wۂ=o[Ũ#d069).K!BT񻖿W_}!n2gQ:6p~77SPE}pW1Nw 1UFH $;`W0E:XK75ʹ5zjT'hMJ:j!PWk8y0!VHr9SXZKɊ,rN(B{&8񦛈p m6q(/Q/B;?2VF*ábRoZ5Pt%)jE,DxVf*,3aQ^ xR($T0bLrt Bdj)1,uZ8Ƒ&;쫅z$[7xs76t؋ Yp@Fȵ- ;!? 9 @r8 khn`LBst?" -]'|꾓,W};3߾`X~կUWuWɒd9xݯ?x.IYa.QAH_ZDx1kTzPJHZ; uM$mתzERVpɬh b\ YԴ:T3&aVEl-^j5Ee,߲&O%V y)Q<"譫J  S,$YDL'% HwfP6d蚮Ϲӕ`cE |2(OH17Pʦ[MN4 5HPk8%HOEQk5]),`L 0J@\LVW]+D/v!`*Y~o4`5T8CQ!F>۠bCVX2 "O%ې?x`\ɋ=E_Wa ?i 9ygrF&m OTnᐠdIPpz =,I' p n32OxJ[L ?!|7ݙz֮tko om/&[j*jLJD?DÀt{  P$%hҲQgL 0&p\~P!^ܺ)vB(BIV7˹11+1Ns<=yN"LNU+tRd>̶r]J!g>KUZ]v!Ys[5) zFN|[P_>w{G}{bԃ_GNK 1mZ QyljӉԇ`QL˥œ.\χQhLېI0+^nZIV6ɟ?P׻'$2eU`AAXmW'eNǶH(y. CQ Z7]Ifcw.]^4nC&Rh[^[Q T"]CKhϑ2;BP:]U!g0$wJ3x}J i&ߎHl(`L 0F*ׅ0:w]A>jH7/b]wz?Z:H=a9+ G?y(bA|RavU u8co 'P~`|*O?(ppznVX^MAITK^gZ_='dRCzd\&f>KV'j)$yӇdLSZAvG_Z}@q>ӿ+d+ܢ2Dx1;j?(T /a|@&gC{bT{G:/ߘ`L ,W4~rBzɀ=C!à$biQj&s <{sWcgXuj'Im{"́ \ex~s +o~رϼ7E<,ŋG،r܇7 E+BKic?FzwSQQ^qn?&olIrH0WEGJӺmQ:#|Y悠()_{n[[,cjKi8~o~"ŝ2_Bbi?yci-/T_ 1CeU'?T{G oW⢎NuM1$OcRP$&`7ܢ5rahPV0c[Ψ:i"٦߁ MPyXamY^!Wtec|ӕ6$ÊSQ̚d` Rq&pYmòD_i/=?WhZ?uI6Dq:M--ocuBRXC53t롱B yxN!mXN7У&=5X =ҡj O5 ( 1sxhSwyAfqx{^\2`L 0w+uxJYw%S1S49`L 0&n6u[V ˉ gL 0&W\0&`L 0I7׃@zV0&`L9_QL 0&`L p]sjX"ItIؔcKP%_2'+WC, |[k)\ŽQTo@^ $*-]oUH6GR 3Vg V:8 SrbLWBkPu{Jf::=HuT̠6\N (&X䟢DEi*ptx_8 ,в0P \6 `aZD2 |K1 (=dnGPXv"=qFIֹVӡe&`׈t[[r?uBM LŶ7 -[4N XxŻ[F>ʂN1*Q8;=?QҡS e޸sH8hP<xBZwhm؀=&4;(Lhtp6H<#i9Vݼq>C-$N[ dˎ%I‚qd[L ?<n RLUK=Kp e`I+=gh+opR3R{zQh^;V! =H;lp` 0ȏJI1&b\ՄmdxP_ׅ0:w]AO&vkH7a]w4Z:H=a9+ G?y(b=?RavU "-8r |\S0+.<6sE,O%Ĕv(\X4 A0 ԍƸznV) ɊV/{]?:Ǡ|(}JƤV9pTkU^}EF(nz X=<.XOjn3C~CGXuj'6m]< \'.+m(S7cyo.ċxz?hMxcqr܇Eǵ*4Oaab9嫮M-I7iR\۶]oó *mrX2~ɋ>jKiƸFvz9DQnf@pB+q` =N)'IX-蚺|9M*>j*NG-ѴS4:duM1\eɜ[cL 0&p\,ZA!{eѼmI>Š mдc֖eɞ-p}0&.aFM3ӕ6$pQ̚q Whp`o@ĺm\Ђk@^*,pW 8XZ? {Ikamfh-̀˵ j zh$k`i>TTN {-'7[VM70`Y\qy E hZ("W)Am3Z]j֙VTk̃!)8sq@s+l28Px@H'4mW\s Z+WGWJL 0&+Z=HZU':W,Y-zGːoѾ4jcZVt&hϒ{FZkW*1Kbh?(t \\3\- | !XF+p @c!$g6!@ոn{KZ䆍 X|5R+m@rׄmR~yÓ|}{@ I h fd<+Vea4@]yPr*R `vM\AmT52W@DؐDŽ(z댵6-B- pqW:KgOãK8:5; uǏ]( zwodM%wUM֩$%J E׊e%6E;`L 0C~oԎKe׍Ò4`h^7{x&_;2&l7}e`LJ[P ]|!qy 0&#psW:&& m3&`L"<"B| ImïGƃηߤr`L 0Fo =NX6o~Rί;O?`L 0N77@>nݺa>ugs`L 0&MWDsT&pxK%ʙ`L 0+&p ל"HBS>\{jdB[ ẻi. Ǚ'/o|囡:g$~uBEՍ%֬}|>7d3Ǔ-UB߱O$ ̆eL 0&+irhMdP<;x4qVI1Q;]TiMOf9]!ԉ3MVʵxgV40FU7'\u{[Z.'$Uq>q3{aRk[UT8Z)^KVq^&3l%`L\ }pt< ?4J~ONn1>W< {/ґc#U :V =b #= %b Lw7f6 0&MW0 v5{e{SKKZ[\ym6~b]{Kۏf0WRfwԭK\cR=CsݺZ_[}SB{תx1Wx5$sǣ]#dP@·5f]K6G_eU'B3 CQ ;K//Ko"&NǞ'& |F(cvȶ&e-\[-Peؑ.ѵК I_5CwXP VkvD!QW6=\u$EmQk=.ْ"f4CV@v4hD$`L 0L*PEF6uu]sétz5{OSeTޣ9֝p4"m,Ft1·|.N`G[EZϋ7&6 _OFz&1%O%)"DJ;.,pHc\=a>xZ:ӺB:Z%RkCTkU^}B:HFH1(7U?|kvošOtug+ܢDCT 4?L&ct$iĚLy~ySlZj/Wx3R`L 0EoX9|\ztg!dHСkaPs0bY5r֐ý̹1=b20T;1XjCdL:X~;dt}>OGEy.ǝ{s!^sxٖ?%xcqR CJwWQލ A" &xixwwmnҡ|x. aTe6(7ջO^2o'#mOD3]k?~\H,'y98ٽqwCE <𮧜r 0p G}ӷq}hah l>E\&U)(`L 0A`GO/FF@IDAT3(+{-F{G41i$@<,CHl+`16|3]iC2, mά^QA] Whp`׋Mw/h*, \1`Bci.I''z_p6Dq:M--ocAQzh`7JT}x I\ lX=2A1Bo`GV&<fQ߸A6 >=t۪۰pޞG7c q`L 7}[E2&`W5]M@Ѫma>`L ~_*X \ q _j`L 0M77kw?8:I?2O}+æ3&`<WxKXjrzjFzF[%SX&`L |lc#dLPIwca2_4M 0&`o `L 0&`L`+x_SSWhõC`Ʉ"0 6i. Ǚ'wߜ콷#gz+G֍%b;Hss:^OƷUEmsop"nJkSh 'T;rj5MдA> _ȷ?`Lv&jk.șYINa de^+8V#Y`a&p k/Ѡstr6;VvӟvDE!)JՖ |s^~s,#VfiâV j;3ә4 0`>UL 0&p\mFE 2M]8-GᇕC~0\RM&?,gMaa4-תʾHGav`X[jгxad^Rи||kkVL/rv1g.)<9T&}+%Lf"mfmn.͚w&f`\A5.9]l{Z\-W2}9l*$(<8Yi>*2sUxP}$g +Qp%/GU/ R(\ [Zx$ ZқݲVcZ@ͷeoL&/-Mt(|,K8{,siRc "ۚ&cFTPPJKr2{ԕH2WFcZµ`M04~ZBXZ4elתn3k5-jZo'B賎O*Sb]];URRN;6`x8mml_ w= 0&?qfQ g:i|OG-$DV1_{0WdVNH7@o!!i Skm}0QŤQR6@ |k(6L> ůz&`ԇ_!\^p} @Pm]ɧ81**  ==3SE Izc,JS(6tV97%ŘN* hlY)~g%H~QP' -r]Q"Iy9Jwtx_8D ,в0P \6_5cv"95bd[95t)J̣g1镲(STt +hzT(щL#1j<4 06Ӄgs%K8=3 >*TP'&`vNqfA?q>@_@`vQC0x=!{w|A; : ޝR%UZbFvJ:<80KW@{2Ԍ30A道@ϒl{Պ:p͓p:X4 .C:ÎoH3fez޸Bi9 HXU+dM={W 䇮uw-tg^\A7t0ƀA78) bV=e =zE4s+3.޳5%cFP Wk2&yA3ZGj-&-*X#;L'5S K/t&`<+J{sx݃{S(êv93?0&s:4ǣ3-´T";J+L)lcׅMęOea2έӅL"0#LZo `a&T s g#vLy1<~ڇ`:.Ck0$xSZ\mV 7ʜTmp!dhZȭm:S>EB%2eUPAK{[y̛ڝBXuZ!yH5* .ݥktSo&jau:ӯm6&] i M7 JD@ӕT$tD;%@3Ъ-L{UE=`:WcF6]už݅p%'"݄nwL5Ζj n#:;gh?'EX4煇xKM`G[E)(ǘ5$c\,xu{ "ZΧIirJ;.,n@hJ=atEĽ]Odc0Ga*È) \or߸f>,ZU{r<A1'gr厪àKy@q>ӿ+]m=Ft0)igD1YjZD39$cDgWYxRHa} \gع}"?~ L;dL 0&h\1߸FWݿY8T2`$p1_=43,(\9F{QjgXNZb!oYvy8=Lwf3ͅxSr"/ub3NU]'B) xn~\,$;Cl:J𚦜etM]|QHg#4lq|KTœ!TQU u7&j.{)>#0^,bL 0wruPV0 f;Ꜧlȩܩ=+-+$==[ aL0]/mV J90fgL 5gWhp`ך@ĺmX6\ϰ$xfY3 Y?pO\ lt6 @lL&89B0ߡEj 73o݂* 9>ϳ`-M-'= mG) a CtJ)W> 0`FKm: QƠ\}U m2&&Z!a:6*ߞX oAH^i&WКMDXMz|BRek,G&WRCIVSpՇJ +cL 0&pXGwAov3 Wµjѣ*cEEϨ jYhM{FE;%# j10 >4_-= /腴>AI E69GXE2ə pH" 0P5v1ٺlMsG~Qje An\V//I^ pUFӺmm@D? kD@jɜ5d+ | @G;jQjkF;Wڧ>ؚ)h-#'\t0qّUc|͵-gL 0&&p MZG`8)1`G(2;r2jvawo?~6"ꖩ٣;>](.]ٽRz|K7q};7c9Ĩ~&*K^M ԡihA meCë2& W CW- &pi޿LQЅE_ѩ[kߡd),u?v/}ߕZ6@7wUM`,?|9n5skbMms<{5_MɟL 0&er 0(fGwhc(INTJv-Dr?.ۜ盂4ۋKI |d:Sz1Tbxlkp#L 0&.Oo_R̙BIX3kA'jLT",Zkj=uV,_G4%\=T |+u6|SV8kAS^XfmPպ@0lSXFVnd×Ǚ`LJB#)I=x~Pi;F/S/LxYNx; {̵T]IDqqVLCҍ&|&7eŹL)8;kϏ_+bX|hM30&8G Tޅ7g2lwϥy\%oar-ӗfOBkrɃ!\uHB[2rǤ${TՇ洟u+1R9+T oKrV rhp4GU1I S4(ݯ'sǶ_swՒUWh1!;&Bw:ʅ{x@/kxDX.u٣nAV 1pg{tK&C䡉4£@8qoih\.5*i ƓSq[ C,71hDf?UqAei`2W>4{L~ IQӪ}9OO], uw;)[إә`L |lW1#ax<X_p'`NE}8Ւnwkj n:;gh?'EX4 \ :dR9t69a!fb³aJ0) \!9l?8ƠS}cz,]O«$$QᘐrP=ջl:T\DTi5Gu C:J&e4 C4F: (jbJ.QkCrݠ|:;RU5z7!_=mg`L W4ؕ~|q;G^p1uűdiхOwԬ\9+{썠?20T;1-F.Ok6іhȣθ<~7/6z\,,w>kLlz*$:u3O/A:p!$>`U+A*⃀oN./"rXXr\ aEK(v m̑esUt’wMs: AE#9`LxEM8\;pۃЦ -yXamYS!dOfLo Nvf F!6fgLEbsXNa׊@Ժmq.8k$Ԓ1\\ @MuDw:MZy.Cz<_;;}tCA .TWD;%-ȶz1B.Ydl6* iBUHKWKlr}JLjЬAu)̃! 8GIZnM\ F'ToDzzC-Zn+2kD}S<֫M 0&$pE붳Ir\[w}fQ2EBwu8 {Iv>dxpG@A/h4c3  tP753v'cepz;MPt718V+i jc0T8[/F }gcyj~]RIkȩ-}[? >Әyo\7}6B}5QTmc:ݴ> po3Kh&Z NLx˸ʅ-&5[j&OYsfrՁNTFGV=T(3N8`L`7[poK?qD!*c`6FUD\&*1A]-??]ɯ DcšcQX\;w8- U7A&(qnr*b +<BEza3 &TF 0&G'ps Y;xͫϟ&*㊛Sckv:g-Ȇ/G޿ z|tu9^rF&-6 \'ih;O5:n٢RcT}_s,n5XtxP1xrV&}5>9lڻG&`L \^}TY'XW>>`L W0pͩ)bD,4SܵH&15BxkNp 0&ηOU_LHe?\^vۜЌoڈ-K&vl Χ|6%iKj#ajm_p |Mf`LF{gkp 0wΝg;co'>ʼVpZe0{_+|2޻UTIwtp{٣kP8h1qriA֭NA!ѯ"<۰NFeڶQQMHB2԰NqV K9|$׮rcK(ts_mT`.~睂a3 _sѤVYDjRn6y`L.;8,< g:mZ|K/^- zɬ-jn胁HCTmC@oa(YIth cL5Qj 52B/gׄ7[| . L:" %kV+B>CnHޔn72^uBUY+g.n6gdMOu IV5ZjcRK7z 3BKym y39Aχz\&p釀~fAo{u.-xop7u,{]3J, ,T T(3>QN޲>::SXklhV]̺Ǚ}~ϻ'Uhy\4&vs² *ٙ)ܮJ%Jis<uas.C rXm}(H ̪杇ՊQ=0k2rw>)J\Y} =E9je 4mL. G0ĔD>"V[]-[6Fl6J\GQ6 dQ'`L 0qXׅ0:;ét5{O`4QeT#Ya8?|xC6# oB>Ba\8'_E~|d Z|A,S:k@0w1 (s~UQ<0>>:c¢ߦɤ4mōlHNzܺLDp9TP(%>N' CG=WQJdCҊۏ-眮߰S^DJ+h"AK\QT'Tv8 x8?”iXt>60&&o(fZKLe:jBdX #_4g0o8 ө 5-`X=Hl37`G@7![;E ^_xnɃ7 p)iR' LmfGzPMe U d okmrH$Fp{\O0 C4)(dxwh堂X˝|IREt$=0Z-40 Tږ]\4x͖j9d+ڐWB9 AYF)OMirhT}`Lb}J_e\rNKAWae: !dOFy['t EBӘY3 DBїLH z\A#!IәeM^-dl6ha<9/xpq+` l붃qȷg%S {CNz0+;G)?` F0z a|!l2havH;c f@P 23Qu;zEyW@AU( s9+IK @aZ_mR0WqXZH[,3&U+VzDCҍ?P'fkբW|=,&5D =4GnxL(InwB2UB3Xo<80w@0ǡ}^(R ]\ ! {h-p\~p`/'O 0@m3P o\Ot6ʽHPbi[FKi@^6ZX3Qj/``ÇmSv"NbE -B^ 73zWKN1ij3cPI{UcL 0&p[ 2?憙 ƨy_;@Y/ّ'kx"ηO~V?#w]^#쒎w0IDx; ~v

MJ_5 oJ˪FKz&vGϋ%gL 0&uow=0U0G5owVW4}DG(bD(*m%/NT`BtTZ*%Qbޑs],qa!,`"3xי 7 {oɖpg,L 0&>x\I<\'&&ďOOrx{x|{sL 0&.+./kg׀H'k` `L |2 \ɬ.׊ hw\q&`L ~&p}@ngoSLl)~ؒc'ۘ-'2('Ob\X[\OelLB ,e0K,UڱfU l"&1$zaW`H u`; ,_^|uo_wOΰ'[o5C1,vfl:߬7C̩OȨ"Ø&@H \¸ah6'mhz+/GEujr:!u >1^fj>ehSI1YEqlL| ,yFV6X dngd',6EV9\r\t!Zx811!\T9)Uň q6oiN3ʲ\LB A=z|tYn'eֻCb[nZ(#éL(LXXBnD EUFIH3vK1`b( lt9T̹x#HSk5Bk|&BU|6%A0XP{b(!4VP2JbvDX֙HDx eҔZ̴JLΌLO3?XTJiAy~: Ec"Hڴ.F af17%/3U2$Xڨ"'IVgHd}JKHq.@H @F_^}qԬCGhW`2N2ׄފ :=ÕКV%HQ4N{T!Edз/E`\I^!]O;We"6~4aoC [ׂ7*qs,(AMvGZ4kV"k9'О1sW@妽mxEqu5~Ťcm=:5BkT8Aj6p6,aa#HInFhHB|%;O~aQR?ƝOnWq)U\s CŲqN^27Buza9(,es#`5H08ǟ?6B`'`*waAH Bj+p0ʬ/mLТ' ]^%4~_GoI%\rPZ..bA;+x|!hXmDI6.&@8ַ/CLbMx7@|DM\Aa=`0{ދ5cvHHZ3 rq|r1(T Ru#wkDY+0ngTaD^Qvƺ|\ɤ`-h^"0 ] N03||yߊQKX!q=EV๶bBG*BwpDt֛?G@H`+1UR۷m%ZLh b^h f2B_uz^y .8R`Pݴް؅:uhRz݂zV/JgEEu& = H4NPРgM'f5 T 0ȳ Ibumh mcrm4gfPG>0 6gԎ}deg@AO,y# !W,ܠ&S4 m' N:-0ש}$ ː29@H`41e4;KaY^.# ^DfDT F7"+]pҍϾq>D@IDAT~Ϟ_l5ZX;{qas*7'g5]^\PQ GE#R VrU솹Xo'hK(% )K$Ҿ4Z$*G@·&^ `]uC׳Ô-"CH{a[Fo 8id)oP#Lzⷢv@H GWg%F@|x>'X~˧5m] itH $pq0H-P ّB8(rWeo'M焷"$ة.z6 8>ݽ8(@H qŅ]$ph]^Uu{nba1@H B;I`>$`{2]sNW0AT@H 68mO˻; uivr|ll|dҢcwRR#$@W+5#B~-Oˉ@H Unt'4* Yuxw鯪rWnA?@o/64_vOXGjw;'s8'w55A݄vi XF)m.%^!$zBmǧHb\w0>JHb ؾiB\^ý&\UҾ#Wo$уcSJ6-0@ι'gý~x$ Wfַ;UGFi}*>bqzBy?A?@HZ +lNB:.^ds0 U EcS(6ʾf$ ؠ޵W|ZZN7$phQU(dk91UlZp^S2mQk6l̶cʣܱ3N\q#14Jg%vprTtQ'ѪûtTCTE$~>1^fBj52b4C(դ,ˍ86&d#U F`b;۞;Y/Yo). ʹQMVBqbT8ĄDŽrjPNWi7EB3)BeY.&Rve=uH>/cVݡdk7~-ӑj| K^b&UCD,! *( iX%PVHDBj92CqD1ݐij$//_cf|,*M=H $,5)Q:R`FZ݉ZE+^w_U٠b-Gulֵ g ńt\=Kk|(AMvDZ4kV"k9'˺qTnWdHWXg[wYZF:ѳޫS)F^{^o9QvfDfظ•в@d"%= )Mѱ^h=I{ Jh$`mQAō y!$BWhtݻb}C #Y8rDEx*>;)k6gߓ\V-.:@6x1rha7 \PPtR@w Y|jBtl6l3Ƣڸ"`%oD2pPFAcM0SJ`800HZaE.f<9@H޶NM,tzOoHËn0]YVN/mME~m|Ϧ V Ĩm.PC^nެиx4~sr[FM;JrDCj^_0LiS EhJzG(vv6H $\3ytyR$o%aH`hMgz׺XZ4BI,aХ)^%Gؖ[NY-[2;p)dLa&k$w3c,;T9?5h6o^y=awOH $ \?a`$'V=j\TP ؄xNEH $p}a6 Ԓ!R UHtH $p\qّB$Jª4ŪZ.֔E@H $pqu1H;V@H $.dT(_6[.yi-  $؁W@x%$@H $0_ K\l* 8i#%67?U宺5,~$.[Dn=IMyGځvn96w`^sݖ'nU Pj&nm3]7ېAnmcdЇ@H,}9{u!Lݬ@~W%:f~‚]Tf[Jyvm+ F7;-L[fL |o ~Z,TY+0BqlH񯙧UIx#״(\TJ"+4Y0a$ؑ¾mtWEὠ9X\5@9[3Z\]e_e @Fw@EM~c'i!u sͼ4UWI6A3 ÿ-~#X߶VoTvv`:>hJ T8/_ r@H FWa\^]I7TxxE{4]y9*ǨhUr:!PU{rt'LH\FdTb,7ؘwc2#K7|^g7y(EZUL\qQ5-.WZӭ.ǵ:uk!&<&ėT*'wvQ!^z464$+Ce^ fܡdk ;j RL>IzTXL%dU(!(<7Xn1^ճ˕eF)'PJͥ *i!TbWP;l9-Jj:*YOML ܄ S Iv>b^REu 6EH FϢ6ЕtzZk_6a f!3]RJ1~'7%JRre!Z&RI@iu}R TL0 *Jr&?I/ LAGȁ'%'ti=Theso^%$*%^uިPHR&Ƥ钛NjWem@"#4h^c B @&BUg _R"4p$04'M]wL-W3$²NUFP,M,Ĥ;\,+ByZgfT)02F KM+=;VxR*@bTX)4U*@Bՙq #PZ:T?DB.s=U+@w^!!&ߢ/h:uH=:BkT8-W!JIS6Ge(5͜FtzYFCk%0lԊRg9`XAyq썏̯W3#e̡ $v pXvӞs<Я@ 9TV]^1F>\旘ee ( [H $pc مBUٸl* OJih*'Bg"K9&:|F\-ggoS.E{|!hi# tGBFgD|0-|4G6Msh^sMMrI:r(H u-fVGU8>IdEx`af=!z}7t!2j5_ec:P!T8{eevkA[K#v>ef ?T K20s;2kDlբ4 l3Kf>3K ~/Ef >$ \qiPmԭHhT X+xI`a\v/Ũ6r**8^`n_8 ,ڹx3!$`ExPV?IO5[%e{ Y/0@wk– pvkEaSʐ2p'X^O єZBCx>ؾmE !=$$QdRY9>^mMJ`*qGxŐ=97(LTa&ήuf`"vo-(2mZ.=ǃ_k{4<8 "j>n#7 67v9DTNt*CATGH $v+ދm4롍|vel!ÏWV"ŘH`mCWRJg#pl'7`X9d\JsՔb. MYB,m?9QHr#.ؓj5+H l NQWZUOIW&ZY/e _÷N&'ZQifZs AT&oZӵZ [a/P:PP/06 Мqh\ 73V@s KJpRvzJ"#Í}Pjlv$[imh&+v*3ѥRC;lwmݰ=rRb9{CJziI0CO+U%+C@Uڷmt#8[֒iJӑh1LS֍`Jz"@5A+ζ!*ό6}d`AuӍƹ4,-v9:F΃"=$TXzf)4j%@4&T:תF͹~qv1ZfoW@-Hd5HBpzRX6ZC `~)s=8BKl8d:4NmQ^O"3&AÔ饠2g)( 0ʳVJXq8 ظb卤2q+e%dGmIAH ]C` Jj4;k:Nܧ]7FËn\YY!ck׭EKcXLÝuMF~wZYȜ əo 3J~TPtKLզ`#r^\ZÿYܦKoo"Y$PDF0%~4EҼ2J~TP :ޗCop5֡)BuH%7LMR&fBH 3 \Ur>X=j1>UjNC @H \uP1d:iԜ{Z L[痰j@H YAHj$Nsr|Ųrt@H a- \%z~9,?}@H $.B+.o#!*(u7b)LH $U$W6&v a^79v2*4kJ~f $ a!CA/JԂ@H` Unt'4k/dv* Kl̯ߥ"]ukYH \cxI3qK^8s w;~{|:_잳H;re׹WZf7ke,Z[W&&7 ?s{9N/םlc ߽wn'6ʾEʡ)pZ,@.Rm9UI BQnmH l"f]>{Uh8{/)63NT>?3[3v̽bAϔ?/ =5*72ߛo?s/C SVY=^!$Z  c3MVвMeA6!,,W!$sTi5t6TlS#$p ~D'%,~e泑ߕ5kZǧn{^r&I>w帙a1)a=Fް].ˤf#$xK|֨VJ1h;+/GEujr:!PU{F)OYdOr1J5)&r(9zx ^Zou?8aߤاI>ݧ> FP_GO<~Ҙx'8q|3y[=F}3/|둏3/^Gl7r/i!oxB_|/э yr /.?S/#G81 @HZJ YiwծvmZ`Fմq.U./TźR;$JR\!V-)_RIʐG!' L^pR6qrivғރn\8495s9E@[ tϜ"o~Gg69tg~?%ǁO{/yң;R/|$l<:?؉?so/~M'$w{] ‡>Q8{;uGX#Ǟ~ؗs oI|,|؆2ٟzν/?'MWX_%νܳ)cxrgӴνfO<{?:6>Stt7]9(tH $v@}}azP@s:\\оr$ nڮ7^PiuJC7T;N֖NË"+H9@_p?\#iѩH %䞇.wya;k/|~T賧NwNH=gp'yɏ~ԇx/B> ﶽw{O[k/3?< }ˑwM}?:^{KV9y> U5'TVЧ3=gN| 5v⎛7k};G'G>iˏ̓'6G+$@;W܂+V(OjW탖PYvy(U|vRl\'7jtZ\XuN0co0ӹt!T XL͊,<0* {C~ $ ׶.9v8wP;vo{/%?s:=ҷO H;԰[Pyڷ^y Q-wΜ$$~ʏ^|)B;xsgG֧97Nk:O}?buF>'B*!*irZ̯9wN߉*\^TtH $ \qu8FUV;*2.,7wyxӞ < H/y`@×mrqy~v,V:UAkJ軿=hk#JBl@ }H ߚV^xsNs>y?Y+3oә}ɩ{_W# vT?ǎdyބ@5)ʹ =9=w=+dzakydwrĜN˓@Wc74`7;yVww{`gt2`h@@H @*+|B%#s3SL##`P!zt!%yU^ Q]VmUp-ΉPy/\:Xʩֈ˰n2NgbGg+|_#3:" nEsN-n= *?~ AQga1w0 Ə 2MP`9|7aS0۰U9q}7!tӿGg~L?m;A ̓_*?+,Ș $5$pm_J >!V2,`Rj>>9JV..jkU:as4I^2?U"٣ .Be#p?BG*T^=/{Z& 'M?@3zs;'  7io1!Np ]bEHS/<"Zt+/~5r;kˊ}?l9_> {6Ƚ4% zM[> Cx&潉Ľ,p5[D1 $!p5+M6k[/{wm8 uKdlN!#Ldnn)7u%:<=DW8Srf;$NO2W&|{"$S߻m1;sI:< sǏ| ߙ^]}+3tg=$gn33{ہG!8'>XzCQGRSBoXܞ;|П'4,~/}.gs10p6IbCr-2r X ȿ4ђ{c=}t7 wpq}gR+ 6Gwҩb^$@;X1`FT؄+C>B1BzQ1 FjWil!_mA0w4LdzosM9st;n~;4?Ǧ&,Gs:Zٷ8z ܈ϩ0%rsr[hW94/-8I\ ,`7ЁN o!$"p+.WQ@&*zmL}`pbe4ޏ7+."D;i`^A7Q, 9al||\de DƧHju\t;@H $\o+ H!,Wֺr;dI&D =֘DK\aRH $%;`Ɛ5 `s8#8As-M? a.kL $Vp\qcH`Ч"`zj;t$bgZЯ $p\#pMc,OgX\@H 85 C#lP%TˠƓB>WO_$@H`7sfwDz#K$߀1>sQP $]Bk|f4d醯gS_>Ef*UeЏ@8z;3oqM>t~yҺ}i`rCٴpj _wȩvs>A)+]ĦRwe4Sxi;tZ]N8}R 3)0BH`7TY&ehHT94n2]HE*-*iA(nn@~~o~+B-B#M7Wd8H˛[ARMpzxG7hTϜ֖iQҬɩ܅2U $pc ɶ@+/{[esЅy!s,=xŮ/ǦWWB $OWVx216 JcU/thn.cr;D6A\l@kv"7%l"``%ihzҕn-Ĩ[NG8=JH:eY\FjojRLFQM $f/}ęZ*د~.G|O\/єyo=_s u,|->n$ >TbuMq+xtk#XF\yU\\1WU@];Pi~xQZMCj՜E͊4lXa\lv[A"nqyPr\H }jL7tkТfM)@Ӽetq Y\L$\R`z%-Z-?\Ma K-]WQJ]&3R5MK*d4~'MIוk J%)CIթ"Fbld*L&Jq:>5ܹDi#$v3OY=s?G?92\H걧jCӉG"䁥u*ܜЇBzIzaǎ'AxR?͂X.<+%ԡ&+ohX@0굘'$eb,<ҢZ&͂TLIR&F\NC[Hd9Yꙡ#6.hW VWjM+ B4$ڕ",rYd5IA) TvSC݅KMAzCm_ ft]\`9*੔x+Cm(@%{z7ނR*+k@Ok\^3HVǬWH:XIB;਱ H- TCF7,Sށe 4+` Y L3`D+jbZ=dHD@H p|\#ұ O!gg7ϝ O2c/?d|\A\X"> ZmƚD`̚/S)xxVo#6p"P烐HI{&tۡޤ]zWIo9R -UX tߢǠN1BhAl l]S۩C>hޔұKj`Ai\1k c\A>6Ǝt F+5 8 ?k7a,f`\e>X~A}L*@W$n4:u ŰȆ*' &|Ubs*+Q./%Nʚ͙F-U +)&ȡ `,sQz~sSۥx`iYrM7wj $4j[xf>,_r~Cw o{a'9^G'Ϟz/Oa#,C ~A:!3ܶ>~`7)Au6wu tm퇩|Wxv!V9 ږn, װB?NTK/Uq9x0 M@c98K* d kN*p.tϋryi/ !Ge 4}P6tFa]Ieeq;k J 22hC%s1]=ڵϸN>-!$p :l\ULB$ ]^%4~_`?^1S%{r\\9:KNULEn<"M\,@㧀]O/|p"W8s3덗©,)9{y_}}?^Xћ9Oc_ƟwpAЇ5yqۡ?aІpT/ n„js~oVY1?KR "BGx}-J[٤H4g3e< J6=UovوGvތM>1 LJj#X&$KX8@K/@7*olwF#sS\ E7|BS *V/> \18~؎]5N%BVe=jOΛ M?H $@ -|[.{QϞ:+}&yfrYg Ǐ}uwDa_6L̐@q2w%Wr| DqOwawmat4xbd@MF #: @3dX1UEt/e>o9JVpE47W^!a s40)O*9]kk:حTF{nBݗϿŏ}/=JkPft}#wUy7"~AlSGL׎+Oۍr^"y3notffXF9ozx>|(rN# O':p.K~]];WhԪy2VRE'1}mK/ =*+Wmcd?,.s͒stXaHA*0JfЛLCIh n>.Fe}QʹUB+asa[RR`sCpt ̽xcs1]ٟfC.Ȩҟ% $pFm: ˚=;"bb~`O"DJz""(ؘVIAnSK d\Yv$=[^o턍d;}G֕21P?KAlކ<(Cƭmc_7&m03M`'# gf0+Xjj{;M7V-˽R TkNo#:k#X7e[Vo=cV) t"W4lHύ7Rh}=9V`(po"zɽ1nRв`9^=?(ֵDMm(=yZTɞX4A) ưױ«.zV%"aH UdE;zЅm_k+z4~s6Ot֣ Wc  e QE]\Yb[ VζtralL7 $\7.\` Ba"Hx $p֖Oo7c"}ù\0 *οYчX *@%X fbT|pR2МkPs<[¦xv2. ccjC؅n]H I@ͻVP9J‡>uC[&ػ@IDATO>w1+wzɼP $cb< @HZPc9{U97.:yu_ضQv6.2"@H \ 81M$N%k[z:aW07o(8ةO  vwv@H`PIߡ;sN20Y!w="@# (Go $Pmà"NBj ݮݕKт2H $k b>z,8@HD@Uq|-$ޗt>{t $(b GH U8AQ $>PLNԦJCVn'Y>8TY[2GH B`7?}n;TF!+Gps!+ 2׊St9X4L82Fl3xv:(UĢl.&eXʡ)pZ,@.Rm9UI B&V<FH *gMSlryFh|ÇӳMOsS[̲Z,S *ũSm[Ob :$. 0Asx^~y٫=f voM-vͺ"@칅{:=m TZ~7!GùkSsI y0wo.lu]> 4@WW5D[v ]y9*NDAVn9*U=JH:eY\FWnդ,ˍ5n $v[&`ۅY!.뚘Tpx6S,[\f\^]`哛^01nu9EUJRQv-63vPr9hsފO-ƫ1PUQHk\mG)rcB\v~ "$npJi^3Tutk` `FZfbH&d\)TR^u-ACY$eh :TR#H,LSY)"ToJT:7Sݹ1gH M.+-0ofeJkVOצ(go "&l,F_P(I1;RhDf8l4ά{$#U@zo$XA/bY#Zͺ{cR)J[LI/2Leu)XzW9 ZM $BAj`\!5mM@hA=@C6&5^t=ÕsZ` Ś4 )DG6)>a @W<0lSuW+v$U`O=xиEG 7g]HIAx@Hbx\k\0 k4 `u0#Roi&R҃P*@lzMzӯg@xIӆ?H N_ʮXer{}9ܾ8!e^&⹆-e |&[ҹx<E1 rMa!?Ղ $[ B0V[E ^gV̭eRsS[O5,P%$MuMBnaƃm懜M疣!a|rA{4i3\7j46_9Jۍ..MתC+r>؃1?if.k3]@H5EyeZ6x2 \bZ\XUq)tHLe M/Rq3 VfB`Z:4IIbgbߋF}L※L `aa@A!T3`_j ʲӟ&ûw4B@Hm츋!ݽJ6fVx#Y~B۷ ; yP4.ݫ0oS%}woMOL$Xc[@fa/eLo҈wY}$`X}8 C _^xoRD ZC\x#$n<cP$ް6al6}}EW>*?U< CH XԮҶߺ=_QBUrSkXԸ`/(7@7.ؖoV[ݷ+.oaCl DD5=s>ZSLL_5cQn sֿ֡ۓC@#d.rnll:K'qK%$;)/<8oGJBuibB@ ;Am"$fp^Usj4v_: $vKxl@aD$ F~X6$#6%\>u $<|Df|0)kEr-Rʵh:u2&Nu` &^YJ@6[{ V1pV*jnl]h ΋E>t)iBd=W}u7C) ^}w+@H $N'DH Fhl3@H .ovz@H $K`_JnpC]STÙ4!"]SՎ>n8@H ._PI﯌8湇W>l|]6Mw.yg; ?0P~g~os1a@H D`+t] EUWkn'0CHbN#3 Ի o\7Yt-Xn%@w/w}{cII}j1㟇h*xS_~\cw>)_Yywa^ -饝y@HFp]r/7xGOLAI>F{x! #?@H48 G 8+iOmV ?٨ QY3;tJA"?^J:c&˅!#F*K䤘JIjV $&{pwWxѷQ¹ Dx}3>ڧb!6 b4 K`Fx6B!** o  1/kt !!Wj)Ƈ, ɚ":^rRfjf:q٧?d.:w?x +m}EXu' E9=|@?¹nQZwiWϦe͟\'[q#,K~CQaV|Kf@H 8~b>#p8l9P1_j0K1+i؈ vl&pjUcZ~p vN'+nLj !$8՗_?HL=؍9xV0z!k]ԤSKxkYV+$DѼ I6©1 .%ͺ%ggga@H 8~h']1B ,`4_!;%J[k[V &Wi`;OjKS 1f|yx=@_mX|}/^}7o!w$:REX@&B*=ݮ@F ɥ<; 3-ykb hm9>\" kՄR[4Ef(VP[-Wo2&$$Y%0+`춿kFd18j+!l Kklm0m 1T¡C6tk#xyu*!hy&U:Iܬ@gt1~h칷xϤ{&!LI=+>ko_+U.tq{B9/.oѳ82ZVFbEE7%TX02?o. ++Lo]*x3@HF`߷mk늲հ[DF 4d0*3!$N?qNJGS5-owYC:uGׯuw_qs~ W`ts5"L$)%Щ /vAr#WC|--\ .+zpn/˻FdtVWH:RL osSCEጧ|ԏT@4(8;|=H D@-X/'ZaflBc=S/@w>_q_؋eO/;omO$΍/Rt[rKh.=@@H|y$@H TK.C@\9/۹=Iz֊͎s 4x2Pn1@G!G2H J@oCzw{/￘m W[7_qn8@H Qzi{ǜnxO+X隓g2V1jEtwX\Ktky=ɻz$IUqaA,vVYXsZ0uStC8 $pZ\zt烙 ` :JhŕʥŅ31F*.. & jg&S CPyDH ^'W\!^R}lsƳP+yOb?8ӱ:\s@H`}_mw!srr Y6_ vj+F ܓr˯1Lk !$ȉ7w% f,Z+tlT^BAtDZ1Hײ!_TJ.$ 1jB䤘JIyUH $0=.8@gjxuvTSAçڙir!$0arX'9٘YMԵ(&(PAi1aCl:*P; b7($D#mҢX!m:J: L $pK s 2؂Dm[M|E:`F,5vv9(!3L!_J*MDN*KH"v=ڈ/UAdKPO5$*CǗ1 $tP'G#զe1 ycC/"w6MBs$QmL{,O1#7GMPد2 %i ,SɀɉP;F걇:3;Tj|uVa]|~Y:֋r*HUخ O0'I V86,#$`\֩eE52rLqGH 2i>n#H`.Io!TaH_`'L4dMC#ЬSj4A!a FM&RLKC}$bF~"$`~F FΚ֭JYI 0<+|_SC| >4{RÄ]0#* xZk>8#D H[V]ޑ^u'n`M,BOβz ~!$p;:((Z`L\B$aeΝuR˧!af~ui7Ns3B(Wt>Juu!:B(B4  H $0e|E޷f9A)n{[u[(\%d}#` mJ8N )ѐ0;JdE^SsR"F/ڷk?΋ }+Kw~k ^ 5Jv~pC BH <'~, #ruW-]';%+Wv/uUx,i9^56~"WJ˫KWm˖)da?N G $ϹhGi8/snE7p~EA\X+hzͺ]n9ay.l JRtv ^*bEsiͬe~_4YUXߐDZ_F'َxVN͒o$m pIx@9FdomqO?f=p*f~ ]NFlgc˰Ʃ yTsfdp vN!xvH $0J8l˾հza4X,aR+%a/O׵!]Mo t%? LEѬNŜ`;^m68P`۷Rhsut7ǁtY0 $pL_q޺1Bq ,`[z( c`l&s.?jKS 1f؟NY@SMV+KPVVx*7SAw#)UJ\1C$klߺ$K ?{TpGaߕXSݼk(Dߤ͕ 5?/]- m̧KJeJ)y1kv!-].n[6?Vri.&3҈^"$n9۱:ئMlo;H75n.cM4 z鵋8 F*P!lk˞>; 6US$Q.5OJ?!0 $N;{{ז2j!N !LQrz1s~$ݶF~ا-M7l~Oz4^#$^;SwK"$$Yy_>>[M!ٮJVaB+RU#n8j,8 B8F8}uP< $nD:Z6G an@H[#$$:'uH $p _q j$ئu $#~ŭc@H $Y!~YH Kyz-GH oQ$@H $p+tUQ!ky8:cq;]SՎ>n8@H i_xǃ?Oǹn VCQT.-3`o`k&Xj $| $SWƒjvv~DfvIc^ۡy"!zWxnC+_ XhP $hk2^ؕϯnшK֌["Z@H ܄Gߎ . u&OApzigx)ӀH $po勽-"Umz=EuBVĂmͤS8a'W30WJ*\aQQAfw*騕D]E~f?a0!].$ 1WY&'dEUJ̌Wb $:g t <.VS> ǡ5o`8b!0/WQ+QY!V(E1mZQD:JcbB(+(r2F*5l6Ѝ1$t:'eNTݶ؆FcϜn#%bƔ3@KI岔Aԓ Ie)CIٮ"PES*TL0r *I{Deh2I@HF}UanaD5FKӬp[5,i{j(HRfHveDkwa STP2Tzuot:$$ڒfI0ULl$ 'ܴn#H<+F]Bo!БvYoJ02!c荜nKKxMcnV)*k m"f0"&S; ImHE6Y@SBW 5K}>E2}s[3W{߮u3_QPlvw$aYFmPd(d #蘆+B%ا|1 pP!Ɛ@S@A#zi 2=N8#rE>ԍM;\8,* O'az~u:Yycd/>7;#byK磰s:tCފB!QC \VjT $N?/%Yޯaagkm~^ުF^ҁE= [;8o0!+IaFiNq ; < FqF{=9/@SE Ⱥ!0욡!bdEi)a7"xX9˟7Rʥm.]U 2E-#`^|ߢdd{ky͒'KV^+mY"m7#;ɍ(, *Kc'=;;_Z&SW/C.&M SRZz(  $8m&|p9Q#f^T8s2d$=tMNx{P ?uOL[asrLTR5&b<fF!BK-F4fl$Iɓ&kmxForP@H [tt{8abHfJfIJ( N(.ڪJ 8S1a]x2fŔq $m!9۰=UlNy;uzcK$'nC'S7@K^[6'vv^ʒ=TXL|qFH AŗIrjeԇh`V/3zusГakhWiXΦ&ofN!2]ڏYY]7@ 8"_ q7&ņxV= j%ϒc?NǮ)$8A3p-(,@ƹVnHx|KH \؈OfkƮێ/[yjxش߁:Nܯ`H-WJNJVi F iN%ckXBҐyc$䤘JIjV $t™1NǰyBGcXJI,%D+%y1Y֕ǘy|tlPȃT$$7/ JR?@1&[VВ+,(h!&1[X5irVdE1^n>3C[;d1d6e(dCSɚ:/ jT$#.4Fn](Ƴ_uEMNsm',d-8@&py[%m,Dm[܅ymdSjm6YG*Z)&kgL/%RQO&hj"' M$f@mYO Se2TN%'3 ef $^+0ZlZ|I :qOh$Q`̖D21,֩*X#O,D#Ό論C>dډo=GhDbOmvJM'k:+1eI DCPG4ˬDP+m' *$V On >֋#ڬ-R\d=0Rs:6]eM bd&G%dl0 c?Bja$Bƌei $LZF.'ahV)fw0 c~jLkKR`v$# ?@H` =zh>4AxoݍW_˄}]: ,v{>Փ``쉘i@3:Ao5pBpҋ;p!zTeRtviL V:LլU aU4H[A?;YW:;D*/ÒJrԚWuP:gRKb-*Z獲^Otҋ1j0>)q~LSrZ_H"K# Lh&!$p0+Z>|`"RO_BjTHͮ#Hu9S v-2;wIm _TcN< $NEr.LWV{ ?ӂx \ox݄[|EKd8 d~c*`+7I@|jz p4u @E i:ݵjUdds8jI)p&Q3j YiR+%96oX*uܭՍ8P7, 81D܋1Zi|J&0Z2&s ɇAq*aʪ 1[Z-}!H VM|aFӾr`KPu,VeآUfULaPo Kx"U4=3l]ɰ &U͆v޸ m7 $n XNoJ`E<ȷ `~t!LRF q47Ԉ)ɚ37`5gSzsYd׫4]Aa@ !j b3H,F̚IAzۢ@pØz`saվPc4#&WnX nuzXĶ[L& qZS qp l l {/=ia>bG} @T2`l7\ԈD dz:>XfرtHm#DfvؙQ?5qz/$&}k48.I<եi44tqTRG{`5h$rBxkࠦd!g~[N-dpiH*}Fj0Upw'vZPC`^əC\^L~oE[6$ fčh/-G)OF6c,,'2>C~ef=b86(awa},];!jĠC,}p92a@H 873CzKgidpdGf"(eMTC?(}pd]fl2\K͈<*+NA*&FH8 ]gHOzE]!$ێy/!앜x]?ְkiȕ^o-F@HX~ŵG[4IDATL[rM<4vs^ <ljѿ~3~>ѿu{cf4\g` v&( |`d$EBj%Ď?rzig'@wqT3wC_Skw9S~ 7w="_۟ sU 藿ț>VC[14ҨA5ӏ-X 3M`:m ȕ駶J+W؅tlTghĨJ:j% Qd/% BҐy%irRLVT$̈y_+F@H` zE"<_5 h o?(cO_#_>{r~Jߍ/ՓQ# x]~KzhY{y9r9w<"di֫WُUXʳez>FK_ڟ>Tqk/2מ-~,FC`ݑ1Y52zKdMCJ5FَRB"-Kc? 1\4+vIE)Ai8'0~:z zc fIW4JxbC׶Z!\Rd{k1P.]sRYʐŹX ˠ{w9]\󩜔Klo{-e;~i~aip?@JB./yy՗'?x鉧>w9}8^bµ?=W}K_(}~=;_|O<>ؓ'=}*Y3|QJhtUi?cO~z >kxچNeKjM ,maZbHwZ; $%bɺV:.-.sJέl*) {kmћ3 K=abx:_E/x>>KP >$VJY1 jU, j{A–]zi> *uG< Qa{ݡs|4mm"-y1)7~ .?KjK[D"R#-: $,BzZwaW ի)[G>lEכHc?էs|H<}k瘦lſw~iYq!6$| SogJ.zszg!x/>/߳ 4—$y43{]d>ӿ$aygB^jmǗ~EKߚS{BPjQsksKMK,kyw;ڶ%N[r)7f$E[!#5"8yx֋}ۅKJ:xK-*:ՍM^;9aQ^WUjtM.ů05ɥl\|C٬V,)@2tmUy9~0@KUp5EFv­ oq[SAÃa?]'"\~_?:wS<\wףp*hoQR,sg՗`= D_p(u* Ͽ͏a~c@ڽ>$_"̱pPs~usHroM|mz1xE.6/Fg_x+!s#)__4?_N' a]Moz'nîsYҒa$ZmT`T0Z2 NNm0 3G`*m/\.&M SRZz{YL˾d|7`hj!_݌`9S@H`z {x!>^w;?;k6 _N<w>= מg{~i+tCYCO^‹ϖ~O\|OL/=ϽبD9sUݯ Q?Lg6ν/4t' <`8p]{ݣ[Oy#ghT ,>ɵc0;B'DY`:\J}}_'h܇<6B?-{Kk &r)嵋%IM9Z]5ʝK|$.7 1PH#oyrx"f5րb!$p o}6aHH5,}p9:CpI0 $n  O}:L;~?/Fsߔ }] ,C`@&59=U׾Y}oy5oƣ_-6~mQa`u0/"L*iH $p tjp>/ΝV4>xJ݁p={G=p&^f}vC}ɝ8r {_M;};ϖ>aiИSڍȩ8Z3M3DAol&o,qnLGH8uPg 8v $A@-wWfJ^$̮쀆#>4ּc4u^PxO3*y<{'^GX $0EuPS@7gIwt9/Qd/[ZujZ=GX5mdž!$pSA $p kVR%67A9y+Hfjl@H;$S$n:9?@HvMCH #\'){;\#+CA$pVEH $)6jf_Z,@7۾HQ!@H d 8&+EuH $pS L_ |\yXaKcx6ۃjGO` $M&K/??+tԎEQTM/r{ޘ~17b4U;vRg5@1laY%0+tU\XKѵ<} ̧k!]eҐii\S@H L"pz `:JhŕʥŅ31Ni 5VZP:IԸJc&B` =: w|b?C<+ۇ%gpz1vv:v]TH $p }_mw!srr Y6!BqqNjq>0uF§&ש1Hrurd2hV0?٨ QٜTQ+1&<5 +˅!#FS%9)&+Rgfļ:LAH 3Ous Xpj*x`Ch5,0J0{b,_zd:r6fFu-)l62x!TPZLX$P2 ԔBX&@x1&3KdQH9DAYlJ!ZUCH ncDm[M|E`F,5^t9(!3LKI岔Qn&rRYʰw+Ez*_d=LS9)tI{Deh2U-CH Ho}HiY-I5r|"Ryl$+0*n mQ76BIZg#&H4FE2`"ցaF יd*P+諃b=/+1sk>z\NҠDfmSdtSm 2`z&րn9a~ u/8UTAh<, Q`P70.KMM4dxIC#ЬSln8PBrIT!#6Y@H Tv{^eeGR}f b%+{e w?Sl9+`|U <3M͈Ѥ}+êI=HJnD@l8, 6*de P:_2@Szi 2{B :x$ā|+Z> 3; y7Ns3B(Wt>JW:zNnb(P^i, P-@H zn5!dpSz~c 3 K{l/u"Pj z8deQ:V g$s.͏N )ѐ0;JlF^SsǠ2kE}c)VJf)!;yswzn?!t!T #!jmYpf S{.\!^_t8/NV_ MxBIbe!]dw?T+եU⫶ekk-~CpDk`Xb $IXk'KC1F^ts?Qąٝ{tܘ~D+gahg\^.bEsi͔ar 9@Xߐͱ_G2^ApD .49R %~#$p' `&`/Id<~ (N1+i؈ vl8 jU@ftCgTLBH $0F@mo$CALiSd'%HYR t]+G -NSg(u٩t>c4ث4Xux2Q7iqN ,Mz%Jj+H !N_q.hx w\ 48"6CƖ*m- 5m0!ɜ{0./xp`b8? $ "|e O`86|XcRJ%Ys`%1]RU8)bn; ; ,zthp(A-ޕ 5/]- c{e>]RVJ/ۗTm%HWJɋ=Xk\xD`d/Z1 h@(c@H#0{B؆Md svnNk.tt ii\3L]\7< f2T[IJSFPpF5LٙQ-5OԎ pS@o0@#v݁/3aag]/b?^[UfԌ`lZyIOO4&i;9vX"t'4"پm7pU7e4> cjtbbgeiS:ᾘGHv'c#:l€ [F;YrR e&4$83`Gs/O.輮w ;7E1yJJ93Ru%ʏc%;. l).[6ز&D "$p m\C+?T3@HL={zo½8خ<ػ<}Q+ujp d"Ӌq'4KO[+!1n蝜jOz< $0S@w0]IzB]RŋV\o!TG ,GpXpA< q & $0Jl5^#$Zez揰fT:@SI+gF!$ :T4%Я%XQ)@H %lSY0 $0Nq&@H $_q<^(@H`s< S@g>c?8v $@H S ]UTt隢nͣXFTe0@H?]_8O?Q͹n KQT.-3`o`&XÑ  $p{BW+Bu5;;Vx ;$v1BM?:-KM =C4dѴui Oijp9E{Ma+UHIt$6$ڢR,DH $'+MW28Ҳqϲ}L}ލ޷ksB]3.{ ff1PA03cWJO:'oB!$pL:(X|Y/6mQfր\ ucN+I(_!Fp:ًX^(#P#C'bPHP(}Ղ $A֋u hw0ðpV/ލUj0?t`aoeD.Coa$L.G 5z-Eaja\Me+O٢/B^OGK$i+ǀcd]Áu`S0jlfv~aVOvE)6W.R-묌fCH  ߷loD ؂/R59cQgYfg w%4xT, M nNl#ܽ MS7%*VϺdb @gto U7-SA1*X՘E9(&#$!kցBܮy~!=3m$h Z[ x8`+6El9v9 m`5Qs"125pXܚ46l͑ѯ@,VL}n8\bfVˎ\dVvIxS..85.`FZp5`*?P4ЌQH KKJ `L 0 6so2۷o(wzwʝ/ƒaT-7gx>ѭ q`+2&&0IT'_~a;|.y|\,V?v?wMdpj;ަ0&$DZ6`L 0!ݓ]C݂ʆ㊇(keL @y j&`F {`b&Vb/`O=F3` f `A㊇:`LPb o\{y|XFdL ,bcL 0&p'þ瞸ƥg@;ca&>|nù<&|C[7f w =E<Tio gjyXL 0&(\|Ͼݟcd":-ȠsjrcI5N\-XBMZY6nllazt[h,Mrm}_oagüڹ}H{,, f'{P̝;iZk|fwꃅ`L=p_?z ?=tg;nݸ5#Zv'Qn-ZlG"Ioeb+'M!D{GK2) ,nx;gT=׏YXڱ`L l3J^9sG騑 tz+ Wb"€nW\@y#ď|jfj UBI%KѰ?̭-+4ڵӃMmXPzAWΎrĬS+%(tw!DP/umV^8݊^؃پ`MO`qK襆30t ׻>KȡC hzW*4e7 Z qC;j Z5(2ޡB_VSjҚtLr94nUߊ/hqlMЈtg*4zr06OUR77Ҙq*0 I <渒v6(zg<=P@ɸSȀfG?V:[\;`B` VKlMe+p#j"c\E<77kڰN7 {gL 0w/ab:ЕL-l4%LURV[>_YX*҆iEΟ~#m:?dP\ 1ԧ_Ag*+|71yq9D-?HF*+ɟؓt=ؑWQNfi-3Р@NZ~FH<j`IV Nm_xCj Cw"Fyc{G$ijθ_uO@I{;7)sxvd4-掎jg|.z*ɝRiքbELpoU7>P>;J'&1tbm?''6^r'?]634{B??A%&NzO%4 7{CSCK(dJeB{c(ѳ>wAE>5(4RQԑbFv*O&A(|רGߜ}xrZ2Ro@F؊)c>vR5b#OjA(`1_gn*H7ٮƴU XA9ЊB>}r*jVx+`D"u! N\W4+v.Dدw+R *vZ?{\iW[@,aN+b s}.n 0&pbSOt@Uڡp4To8y~Fc>V) ŊVɋgq"cAy:p=7{nĵ[{A}lϨ5 #dSп+POt 89L,'sBえj1P"h1ċo𥳇7M#T"ngh̅& 5=v=sfG$*s'tZ/z6 ~sL ]6$7miud<8od #W9MS7l £65`֗>(gtrUX `L l5[Hq= 1l֔'۸Q S% 鰁{駠Z/cJ]T-ܝحDC`V:Ǝ}Pkøp<54H|qC`Lay<08(7zc"G1dC- >p:S5@8z+mט6 ̠c0&p6'~ׂ1LZgJ@ #,,H"˫)LشXY6: .?dR kx5t " `L l5ȸb'}!. Fe¯mM ! NUp6!a^6hڂf@NcT"FW a3 վrdQy^Nm3ȓÊP?@mjms2]jAى*UTAE zW|HU!C0qy"葮E4`hG`FGE+aϷ!ݴtrS@᥇kkq|\SP &vV(Ht!38`NSxe/g` LtG nofgX]@xpbL 0+`ѯSMYv D=`{G8*pؿTH=m/9E/A )He~Wb HtC[W_Q.e<Otjq92BCq =.iSv{F<&gʜ!L VeHч&MM\RZ^ `L F?w6¾N7bV/~ŚQd4b&w6( 8bpv~oDO4p~ha% ݅ BB]'/Zk_H_Sn7r׻ʇ:Y{u= Fx\[Ds \`#/Yw 7n$z. ;B%apmוK5׋>-kK]D|WlM 0&`L |ܱm `LfW_ox/??{+g=`<>-wlزg Nl{z$T%wKMݸݭvI˟ MJ<2 9#9 IIENDB`incubator-htrace-3.1.0/htrace-hbase/src/000077500000000000000000000000001245601110500200555ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/000077500000000000000000000000001245601110500210015ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/000077500000000000000000000000001245601110500217225ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/000077500000000000000000000000001245601110500225115ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/000077500000000000000000000000001245601110500237325ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/000077500000000000000000000000001245601110500252005ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/HBaseHTraceConfiguration.java000066400000000000000000000031271245601110500326470ustar00rootroot00000000000000/** * 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 org.apache.htrace; import org.apache.hadoop.conf.Configuration; import org.apache.htrace.HTraceConfiguration; /** * Meshes {@link HTraceConfiguration} to {@link Configuration} * @author stack * */ public class HBaseHTraceConfiguration extends HTraceConfiguration { public static final String KEY_PREFIX = "hbase.htrace."; private final Configuration conf; public HBaseHTraceConfiguration(Configuration conf) { this.conf = conf; } @Override public String get(String key) { return conf.get(KEY_PREFIX + key); } @Override public String get(String key, String defaultValue) { return conf.get(KEY_PREFIX + key, defaultValue); } @Override public boolean getBoolean(String key, boolean defaultValue) { return conf.getBoolean(KEY_PREFIX + key, defaultValue); } }incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/HBaseSpanReceiverHost.java000066400000000000000000000067401245601110500322010ustar00rootroot00000000000000/** * 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 org.apache.htrace; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.htrace.SpanReceiver; import org.apache.htrace.Trace; /** * This class provides functions for reading the names of SpanReceivers from * hbase-site.xml, adding those SpanReceivers to the Tracer, and closing those * SpanReceivers when appropriate. */ public class HBaseSpanReceiverHost { public static final String SPAN_RECEIVERS_CONF_KEY = "hbase.trace.spanreceiver.classes"; private static final Log LOG = LogFactory.getLog(HBaseSpanReceiverHost.class); private Collection receivers; private Configuration conf; private boolean closed = false; private static enum SingletonHolder { INSTANCE; Object lock = new Object(); HBaseSpanReceiverHost host = null; } public static HBaseSpanReceiverHost getInstance(Configuration conf) { synchronized (SingletonHolder.INSTANCE.lock) { if (SingletonHolder.INSTANCE.host != null) { return SingletonHolder.INSTANCE.host; } HBaseSpanReceiverHost host = new HBaseSpanReceiverHost(conf); host.loadSpanReceivers(); SingletonHolder.INSTANCE.host = host; return SingletonHolder.INSTANCE.host; } } HBaseSpanReceiverHost(Configuration conf) { receivers = new HashSet(); this.conf = conf; } /** * Reads the names of classes specified in the * "hbase.trace.spanreceiver.classes" property and instantiates and registers * them with the Tracer as SpanReceiver's. * */ public void loadSpanReceivers() { String[] receiverNames = conf.getStrings(SPAN_RECEIVERS_CONF_KEY); if (receiverNames == null || receiverNames.length == 0) { return; } SpanReceiverBuilder builder = new SpanReceiverBuilder(new HBaseHTraceConfiguration(this.conf)); for (String className : receiverNames) { SpanReceiver receiver = builder.spanReceiverClass(className.trim()).build(); if (receiver != null) { receivers.add(receiver); LOG.info("SpanReceiver " + className + " was loaded successfully."); } } for (SpanReceiver rcvr : receivers) { Trace.addReceiver(rcvr); } } /** * Calls close() on all SpanReceivers created by this HBaseSpanReceiverHost. */ public synchronized void closeReceivers() { if (closed) return; closed = true; for (SpanReceiver rcvr : receivers) { try { rcvr.close(); } catch (IOException e) { LOG.warn("Unable to close SpanReceiver correctly: " + e.getMessage(), e); } } } }incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/impl/000077500000000000000000000000001245601110500261415ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/impl/HBaseSpanReceiver.java000066400000000000000000000324371245601110500323060ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.ConnectionFactory; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.util.Bytes; import org.apache.htrace.HBaseHTraceConfiguration; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Sampler; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import org.apache.htrace.SpanReceiverBuilder; import org.apache.htrace.TimelineAnnotation; import org.apache.htrace.Trace; import org.apache.htrace.TraceScope; import org.apache.htrace.protobuf.generated.SpanProtos; import com.google.common.util.concurrent.ThreadFactoryBuilder; /** * HBase is an open source distributed datastore. * This span receiver store spans into HBase. * HTrace spans are queued into a blocking queue. * From there background worker threads will send them * to a HBase database. */ public class HBaseSpanReceiver implements SpanReceiver { private static final Log LOG = LogFactory.getLog(HBaseSpanReceiver.class); public static final String COLLECTOR_QUORUM_KEY = "htrace.hbase.collector-quorum"; public static final String DEFAULT_COLLECTOR_QUORUM = "127.0.0.1"; public static final String ZOOKEEPER_CLIENT_PORT_KEY = "htrace.hbase.zookeeper.property.clientPort"; public static final int DEFAULT_ZOOKEEPER_CLIENT_PORT = 2181; public static final String ZOOKEEPER_ZNODE_PARENT_KEY = "htrace.hbase.zookeeper.znode.parent"; public static final String DEFAULT_ZOOKEEPER_ZNODE_PARENT = "/hbase"; public static final String NUM_THREADS_KEY = "htrace.hbase.num-threads"; public static final int DEFAULT_NUM_THREADS = 1; public static final String MAX_SPAN_BATCH_SIZE_KEY = "htrace.hbase.batch.size"; public static final int DEFAULT_MAX_SPAN_BATCH_SIZE = 100; public static final String TABLE_KEY = "htrace.hbase.table"; public static final String DEFAULT_TABLE = "htrace"; public static final String COLUMNFAMILY_KEY = "htrace.hbase.columnfamily"; public static final String DEFAULT_COLUMNFAMILY = "s"; public static final String INDEXFAMILY_KEY = "htrace.hbase.indexfamily"; public static final String DEFAULT_INDEXFAMILY = "i"; public static final byte[] INDEX_SPAN_QUAL = Bytes.toBytes("s"); public static final byte[] INDEX_TIME_QUAL = Bytes.toBytes("t"); /** * How long this receiver will try and wait for all threads to shutdown. */ private static final int SHUTDOWN_TIMEOUT = 30; /** * How many errors in a row before we start dropping traces on the floor. */ private static final int MAX_ERRORS = 10; /** * The queue that will get all HTrace spans that are to be sent. */ private final BlockingQueue queue; /** * Boolean used to signal that the threads should end. */ private final AtomicBoolean running = new AtomicBoolean(true); /** * The thread factory used to create new ExecutorService. *

* This will be the same factory for the lifetime of this object so that * no thread names will ever be duplicated. */ private final ThreadFactory tf; private ExecutorService service; private final HTraceConfiguration conf; private final Configuration hconf; private final byte[] table; private final byte[] cf; private final byte[] icf; private final int maxSpanBatchSize; public HBaseSpanReceiver(HTraceConfiguration conf) { this.queue = new ArrayBlockingQueue(1000); this.tf = new ThreadFactoryBuilder().setDaemon(true) .setNameFormat("hbaseSpanReceiver-%d") .build(); this.conf = conf; this.hconf = HBaseConfiguration.create(); this.table = Bytes.toBytes(conf.get(TABLE_KEY, DEFAULT_TABLE)); this.cf = Bytes.toBytes(conf.get(COLUMNFAMILY_KEY, DEFAULT_COLUMNFAMILY)); this.icf = Bytes.toBytes(conf.get(INDEXFAMILY_KEY, DEFAULT_INDEXFAMILY)); this.maxSpanBatchSize = conf.getInt(MAX_SPAN_BATCH_SIZE_KEY, DEFAULT_MAX_SPAN_BATCH_SIZE); String quorum = conf.get(COLLECTOR_QUORUM_KEY, DEFAULT_COLLECTOR_QUORUM); hconf.set(HConstants.ZOOKEEPER_QUORUM, quorum); String znodeParent = conf.get(ZOOKEEPER_ZNODE_PARENT_KEY, DEFAULT_ZOOKEEPER_ZNODE_PARENT); hconf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, znodeParent); int clientPort = conf.getInt(ZOOKEEPER_CLIENT_PORT_KEY, DEFAULT_ZOOKEEPER_CLIENT_PORT); hconf.setInt(HConstants.ZOOKEEPER_CLIENT_PORT, clientPort); // If there are already threads runnnig tear them down. if (this.service != null) { this.service.shutdownNow(); this.service = null; } int numThreads = conf.getInt(NUM_THREADS_KEY, DEFAULT_NUM_THREADS); this.service = Executors.newFixedThreadPool(numThreads, tf); for (int i = 0; i < numThreads; i++) { this.service.submit(new WriteSpanRunnable()); } } private class WriteSpanRunnable implements Runnable { private Connection hconnection; private Table htable; public WriteSpanRunnable() { } /** * This runnable sends a HTrace span to the HBase. */ @Override public void run() { SpanProtos.Span.Builder sbuilder = SpanProtos.Span.newBuilder(); SpanProtos.TimelineAnnotation.Builder tlbuilder = SpanProtos.TimelineAnnotation.newBuilder(); List dequeuedSpans = new ArrayList(maxSpanBatchSize); long errorCount = 0; while (running.get() || queue.size() > 0) { Span firstSpan = null; try { // Block for up to a second. to try and get a span. // We only block for a little bit in order to notice // if the running value has changed firstSpan = queue.poll(1, TimeUnit.SECONDS); // If the poll was successful then it's possible that there // will be other spans to get. Try and get them. if (firstSpan != null) { // Add the first one that we got dequeuedSpans.add(firstSpan); // Try and get up to 100 queues queue.drainTo(dequeuedSpans, maxSpanBatchSize - 1); } } catch (InterruptedException ie) { // Ignored. } startClient(); if (dequeuedSpans.isEmpty()) { try { this.htable.flushCommits(); } catch (IOException e) { LOG.error("failed to flush writes to HBase."); closeClient(); } continue; } try { for (Span span : dequeuedSpans) { sbuilder.clear() .setTraceId(span.getTraceId()) .setParentId(span.getParentId()) .setStart(span.getStartTimeMillis()) .setStop(span.getStopTimeMillis()) .setSpanId(span.getSpanId()) .setProcessId(span.getProcessId()) .setDescription(span.getDescription()); for (TimelineAnnotation ta : span.getTimelineAnnotations()) { sbuilder.addTimeline(tlbuilder.clear() .setTime(ta.getTime()) .setMessage(ta.getMessage()) .build()); } Put put = new Put(Bytes.toBytes(span.getTraceId())); put.add(HBaseSpanReceiver.this.cf, sbuilder.build().toByteArray(), null); if (span.getParentId() == Span.ROOT_SPAN_ID) { put.add(HBaseSpanReceiver.this.icf, INDEX_TIME_QUAL, Bytes.toBytes(span.getStartTimeMillis())); put.add(HBaseSpanReceiver.this.icf, INDEX_SPAN_QUAL, sbuilder.build().toByteArray()); } this.htable.put(put); } // clear the list for the next time through. dequeuedSpans.clear(); // reset the error counter. errorCount = 0; } catch (Exception e) { errorCount += 1; // If there have been ten errors in a row start dropping things. if (errorCount < MAX_ERRORS) { try { queue.addAll(dequeuedSpans); } catch (IllegalStateException ex) { LOG.error("Drop " + dequeuedSpans.size() + " span(s) because writing to HBase failed."); } } closeClient(); try { // Since there was an error sleep just a little bit to try and allow the // HBase some time to recover. Thread.sleep(500); } catch (InterruptedException e1) { // Ignored } } } closeClient(); } /** * Close out the connection. */ private void closeClient() { // close out the transport. try { if (this.htable != null) { this.htable.close(); this.htable = null; } if (this.hconnection != null) { this.hconnection.close(); this.hconnection = null; } } catch (IOException e) { LOG.warn("Failed to close HBase connection. " + e.getMessage()); } } /** * Re-connect to HBase */ private void startClient() { if (this.htable == null) { try { hconnection = ConnectionFactory.createConnection(hconf); htable = hconnection.getTable(TableName.valueOf(table)); } catch (IOException e) { LOG.warn("Failed to create HBase connection. " + e.getMessage()); } } } } /** * Close the receiver. *

* This tries to shutdown thread pool. * * @throws IOException */ @Override public void close() throws IOException { running.set(false); service.shutdown(); try { if (!service.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) { LOG.error("Was not able to process all remaining spans upon closing in: " + SHUTDOWN_TIMEOUT + " " + TimeUnit.SECONDS + ". Left Spans could be dropped."); } } catch (InterruptedException e1) { LOG.warn("Thread interrupted when terminating executor.", e1); } } @Override public void receiveSpan(Span span) { if (running.get()) { try { this.queue.add(span); } catch (IllegalStateException e) { // todo: supress repeating error logs. LOG.error("Error trying to append span (" + span.getDescription() + ") to the queue. Blocking Queue was full."); } } } /** * Run basic test. Adds span to an existing htrace table in an existing hbase setup. * Requires a running hbase to send the traces too with an already created trace * table (Default table name is 'htrace' with column families 's' and 'i'). * @throws IOException */ public static void main(String[] args) throws Exception { SpanReceiverBuilder builder = new SpanReceiverBuilder(new HBaseHTraceConfiguration(HBaseConfiguration.create())); SpanReceiver receiver = builder.spanReceiverClass(HBaseSpanReceiver.class.getName()).build(); Trace.addReceiver(receiver); TraceScope parent = Trace.startSpan("HBaseSpanReceiver.main.parent", Sampler.ALWAYS); Thread.sleep(10); long traceid = parent.getSpan().getTraceId(); TraceScope child1 = Trace.startSpan("HBaseSpanReceiver.main.child.1"); Thread.sleep(10); TraceScope child2 = Trace.startSpan("HBaseSpanReceiver.main.child.2", parent.getSpan()); Thread.sleep(10); TraceScope gchild = Trace.startSpan("HBaseSpanReceiver.main.grandchild"); Trace.addTimelineAnnotation("annotation 1."); Thread.sleep(10); Trace.addTimelineAnnotation("annotation 2."); gchild.close(); Thread.sleep(10); child2.close(); Thread.sleep(10); child1.close(); parent.close(); receiver.close(); System.out.println("trace id: " + traceid); } }incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/protobuf/000077500000000000000000000000001245601110500270405ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/protobuf/generated/000077500000000000000000000000001245601110500307765ustar00rootroot00000000000000SpanProtos.java000066400000000000000000002223771245601110500337070ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/protobuf/generated// Generated by the protocol buffer compiler. DO NOT EDIT! // source: Span.proto package org.apache.htrace.protobuf.generated; public final class SpanProtos { private SpanProtos() {} public static void registerAllExtensions( com.google.protobuf.ExtensionRegistry registry) { } public interface TimelineAnnotationOrBuilder extends com.google.protobuf.MessageOrBuilder { // required int64 time = 1; /** * required int64 time = 1; */ boolean hasTime(); /** * required int64 time = 1; */ long getTime(); // required string message = 2; /** * required string message = 2; */ boolean hasMessage(); /** * required string message = 2; */ java.lang.String getMessage(); /** * required string message = 2; */ com.google.protobuf.ByteString getMessageBytes(); } /** * Protobuf type {@code TimelineAnnotation} */ public static final class TimelineAnnotation extends com.google.protobuf.GeneratedMessage implements TimelineAnnotationOrBuilder { // Use TimelineAnnotation.newBuilder() to construct. private TimelineAnnotation(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); this.unknownFields = builder.getUnknownFields(); } private TimelineAnnotation(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } private static final TimelineAnnotation defaultInstance; public static TimelineAnnotation getDefaultInstance() { return defaultInstance; } public TimelineAnnotation getDefaultInstanceForType() { return defaultInstance; } private final com.google.protobuf.UnknownFieldSet unknownFields; @java.lang.Override public final com.google.protobuf.UnknownFieldSet getUnknownFields() { return this.unknownFields; } private TimelineAnnotation( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { initFields(); int mutable_bitField0_ = 0; com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder(); try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; default: { if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { done = true; } break; } case 8: { bitField0_ |= 0x00000001; time_ = input.readInt64(); break; } case 18: { bitField0_ |= 0x00000002; message_ = input.readBytes(); break; } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(this); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException( e.getMessage()).setUnfinishedMessage(this); } finally { this.unknownFields = unknownFields.build(); makeExtensionsImmutable(); } } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_TimelineAnnotation_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_TimelineAnnotation_fieldAccessorTable .ensureFieldAccessorsInitialized( org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.class, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder.class); } public static com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { public TimelineAnnotation parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return new TimelineAnnotation(input, extensionRegistry); } }; @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } private int bitField0_; // required int64 time = 1; public static final int TIME_FIELD_NUMBER = 1; private long time_; /** * required int64 time = 1; */ public boolean hasTime() { return ((bitField0_ & 0x00000001) == 0x00000001); } /** * required int64 time = 1; */ public long getTime() { return time_; } // required string message = 2; public static final int MESSAGE_FIELD_NUMBER = 2; private java.lang.Object message_; /** * required string message = 2; */ public boolean hasMessage() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** * required string message = 2; */ public java.lang.String getMessage() { java.lang.Object ref = message_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { message_ = s; } return s; } } /** * required string message = 2; */ public com.google.protobuf.ByteString getMessageBytes() { java.lang.Object ref = message_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); message_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } private void initFields() { time_ = 0L; message_ = ""; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) return isInitialized == 1; if (!hasTime()) { memoizedIsInitialized = 0; return false; } if (!hasMessage()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); if (((bitField0_ & 0x00000001) == 0x00000001)) { output.writeInt64(1, time_); } if (((bitField0_ & 0x00000002) == 0x00000002)) { output.writeBytes(2, getMessageBytes()); } getUnknownFields().writeTo(output); } private int memoizedSerializedSize = -1; public int getSerializedSize() { int size = memoizedSerializedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) == 0x00000001)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(1, time_); } if (((bitField0_ & 0x00000002) == 0x00000002)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(2, getMessageBytes()); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; } private static final long serialVersionUID = 0L; @java.lang.Override protected java.lang.Object writeReplace() throws java.io.ObjectStreamException { return super.writeReplace(); } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation)) { return super.equals(obj); } org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation other = (org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation) obj; boolean result = true; result = result && (hasTime() == other.hasTime()); if (hasTime()) { result = result && (getTime() == other.getTime()); } result = result && (hasMessage() == other.hasMessage()); if (hasMessage()) { result = result && getMessage() .equals(other.getMessage()); } result = result && getUnknownFields().equals(other.getUnknownFields()); return result; } private int memoizedHashCode = 0; @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptorForType().hashCode(); if (hasTime()) { hash = (37 * hash) + TIME_FIELD_NUMBER; hash = (53 * hash) + hashLong(getTime()); } if (hasMessage()) { hash = (37 * hash) + MESSAGE_FIELD_NUMBER; hash = (53 * hash) + getMessage().hashCode(); } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom(java.io.InputStream input) throws java.io.IOException { return PARSER.parseFrom(input); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseFrom(input, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return PARSER.parseDelimitedFrom(input); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseDelimitedFrom(input, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return PARSER.parseFrom(input); } public static org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseFrom(input, extensionRegistry); } public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder(org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code TimelineAnnotation} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotationOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_TimelineAnnotation_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_TimelineAnnotation_fieldAccessorTable .ensureFieldAccessorsInitialized( org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.class, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder.class); } // Construct using org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { } } private static Builder create() { return new Builder(); } public Builder clear() { super.clear(); time_ = 0L; bitField0_ = (bitField0_ & ~0x00000001); message_ = ""; bitField0_ = (bitField0_ & ~0x00000002); return this; } public Builder clone() { return create().mergeFrom(buildPartial()); } public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_TimelineAnnotation_descriptor; } public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation getDefaultInstanceForType() { return org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.getDefaultInstance(); } public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation build() { org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation buildPartial() { org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation result = new org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { to_bitField0_ |= 0x00000001; } result.time_ = time_; if (((from_bitField0_ & 0x00000002) == 0x00000002)) { to_bitField0_ |= 0x00000002; } result.message_ = message_; result.bitField0_ = to_bitField0_; onBuilt(); return result; } public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation) { return mergeFrom((org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation other) { if (other == org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.getDefaultInstance()) return this; if (other.hasTime()) { setTime(other.getTime()); } if (other.hasMessage()) { bitField0_ |= 0x00000002; message_ = other.message_; onChanged(); } this.mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { if (!hasTime()) { return false; } if (!hasMessage()) { return false; } return true; } public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation parsedMessage = null; try { parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { parsedMessage = (org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation) e.getUnfinishedMessage(); throw e; } finally { if (parsedMessage != null) { mergeFrom(parsedMessage); } } return this; } private int bitField0_; // required int64 time = 1; private long time_ ; /** * required int64 time = 1; */ public boolean hasTime() { return ((bitField0_ & 0x00000001) == 0x00000001); } /** * required int64 time = 1; */ public long getTime() { return time_; } /** * required int64 time = 1; */ public Builder setTime(long value) { bitField0_ |= 0x00000001; time_ = value; onChanged(); return this; } /** * required int64 time = 1; */ public Builder clearTime() { bitField0_ = (bitField0_ & ~0x00000001); time_ = 0L; onChanged(); return this; } // required string message = 2; private java.lang.Object message_ = ""; /** * required string message = 2; */ public boolean hasMessage() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** * required string message = 2; */ public java.lang.String getMessage() { java.lang.Object ref = message_; if (!(ref instanceof java.lang.String)) { java.lang.String s = ((com.google.protobuf.ByteString) ref) .toStringUtf8(); message_ = s; return s; } else { return (java.lang.String) ref; } } /** * required string message = 2; */ public com.google.protobuf.ByteString getMessageBytes() { java.lang.Object ref = message_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); message_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * required string message = 2; */ public Builder setMessage( java.lang.String value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000002; message_ = value; onChanged(); return this; } /** * required string message = 2; */ public Builder clearMessage() { bitField0_ = (bitField0_ & ~0x00000002); message_ = getDefaultInstance().getMessage(); onChanged(); return this; } /** * required string message = 2; */ public Builder setMessageBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000002; message_ = value; onChanged(); return this; } // @@protoc_insertion_point(builder_scope:TimelineAnnotation) } static { defaultInstance = new TimelineAnnotation(true); defaultInstance.initFields(); } // @@protoc_insertion_point(class_scope:TimelineAnnotation) } public interface SpanOrBuilder extends com.google.protobuf.MessageOrBuilder { // required int64 trace_id = 1; /** * required int64 trace_id = 1; */ boolean hasTraceId(); /** * required int64 trace_id = 1; */ long getTraceId(); // required int64 parent_id = 2; /** * required int64 parent_id = 2; */ boolean hasParentId(); /** * required int64 parent_id = 2; */ long getParentId(); // required int64 start = 3; /** * required int64 start = 3; */ boolean hasStart(); /** * required int64 start = 3; */ long getStart(); // required int64 stop = 4; /** * required int64 stop = 4; */ boolean hasStop(); /** * required int64 stop = 4; */ long getStop(); // required int64 span_id = 5; /** * required int64 span_id = 5; */ boolean hasSpanId(); /** * required int64 span_id = 5; */ long getSpanId(); // required string process_id = 6; /** * required string process_id = 6; */ boolean hasProcessId(); /** * required string process_id = 6; */ java.lang.String getProcessId(); /** * required string process_id = 6; */ com.google.protobuf.ByteString getProcessIdBytes(); // required string description = 7; /** * required string description = 7; */ boolean hasDescription(); /** * required string description = 7; */ java.lang.String getDescription(); /** * required string description = 7; */ com.google.protobuf.ByteString getDescriptionBytes(); // repeated .TimelineAnnotation timeline = 8; /** * repeated .TimelineAnnotation timeline = 8; */ java.util.List getTimelineList(); /** * repeated .TimelineAnnotation timeline = 8; */ org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation getTimeline(int index); /** * repeated .TimelineAnnotation timeline = 8; */ int getTimelineCount(); /** * repeated .TimelineAnnotation timeline = 8; */ java.util.List getTimelineOrBuilderList(); /** * repeated .TimelineAnnotation timeline = 8; */ org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotationOrBuilder getTimelineOrBuilder( int index); } /** * Protobuf type {@code Span} */ public static final class Span extends com.google.protobuf.GeneratedMessage implements SpanOrBuilder { // Use Span.newBuilder() to construct. private Span(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); this.unknownFields = builder.getUnknownFields(); } private Span(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } private static final Span defaultInstance; public static Span getDefaultInstance() { return defaultInstance; } public Span getDefaultInstanceForType() { return defaultInstance; } private final com.google.protobuf.UnknownFieldSet unknownFields; @java.lang.Override public final com.google.protobuf.UnknownFieldSet getUnknownFields() { return this.unknownFields; } private Span( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { initFields(); int mutable_bitField0_ = 0; com.google.protobuf.UnknownFieldSet.Builder unknownFields = com.google.protobuf.UnknownFieldSet.newBuilder(); try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; default: { if (!parseUnknownField(input, unknownFields, extensionRegistry, tag)) { done = true; } break; } case 8: { bitField0_ |= 0x00000001; traceId_ = input.readInt64(); break; } case 16: { bitField0_ |= 0x00000002; parentId_ = input.readInt64(); break; } case 24: { bitField0_ |= 0x00000004; start_ = input.readInt64(); break; } case 32: { bitField0_ |= 0x00000008; stop_ = input.readInt64(); break; } case 40: { bitField0_ |= 0x00000010; spanId_ = input.readInt64(); break; } case 50: { bitField0_ |= 0x00000020; processId_ = input.readBytes(); break; } case 58: { bitField0_ |= 0x00000040; description_ = input.readBytes(); break; } case 66: { if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) { timeline_ = new java.util.ArrayList(); mutable_bitField0_ |= 0x00000080; } timeline_.add(input.readMessage(org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.PARSER, extensionRegistry)); break; } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(this); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException( e.getMessage()).setUnfinishedMessage(this); } finally { if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) { timeline_ = java.util.Collections.unmodifiableList(timeline_); } this.unknownFields = unknownFields.build(); makeExtensionsImmutable(); } } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_Span_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_Span_fieldAccessorTable .ensureFieldAccessorsInitialized( org.apache.htrace.protobuf.generated.SpanProtos.Span.class, org.apache.htrace.protobuf.generated.SpanProtos.Span.Builder.class); } public static com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { public Span parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return new Span(input, extensionRegistry); } }; @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } private int bitField0_; // required int64 trace_id = 1; public static final int TRACE_ID_FIELD_NUMBER = 1; private long traceId_; /** * required int64 trace_id = 1; */ public boolean hasTraceId() { return ((bitField0_ & 0x00000001) == 0x00000001); } /** * required int64 trace_id = 1; */ public long getTraceId() { return traceId_; } // required int64 parent_id = 2; public static final int PARENT_ID_FIELD_NUMBER = 2; private long parentId_; /** * required int64 parent_id = 2; */ public boolean hasParentId() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** * required int64 parent_id = 2; */ public long getParentId() { return parentId_; } // required int64 start = 3; public static final int START_FIELD_NUMBER = 3; private long start_; /** * required int64 start = 3; */ public boolean hasStart() { return ((bitField0_ & 0x00000004) == 0x00000004); } /** * required int64 start = 3; */ public long getStart() { return start_; } // required int64 stop = 4; public static final int STOP_FIELD_NUMBER = 4; private long stop_; /** * required int64 stop = 4; */ public boolean hasStop() { return ((bitField0_ & 0x00000008) == 0x00000008); } /** * required int64 stop = 4; */ public long getStop() { return stop_; } // required int64 span_id = 5; public static final int SPAN_ID_FIELD_NUMBER = 5; private long spanId_; /** * required int64 span_id = 5; */ public boolean hasSpanId() { return ((bitField0_ & 0x00000010) == 0x00000010); } /** * required int64 span_id = 5; */ public long getSpanId() { return spanId_; } // required string process_id = 6; public static final int PROCESS_ID_FIELD_NUMBER = 6; private java.lang.Object processId_; /** * required string process_id = 6; */ public boolean hasProcessId() { return ((bitField0_ & 0x00000020) == 0x00000020); } /** * required string process_id = 6; */ public java.lang.String getProcessId() { java.lang.Object ref = processId_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { processId_ = s; } return s; } } /** * required string process_id = 6; */ public com.google.protobuf.ByteString getProcessIdBytes() { java.lang.Object ref = processId_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); processId_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } // required string description = 7; public static final int DESCRIPTION_FIELD_NUMBER = 7; private java.lang.Object description_; /** * required string description = 7; */ public boolean hasDescription() { return ((bitField0_ & 0x00000040) == 0x00000040); } /** * required string description = 7; */ public java.lang.String getDescription() { java.lang.Object ref = description_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { description_ = s; } return s; } } /** * required string description = 7; */ public com.google.protobuf.ByteString getDescriptionBytes() { java.lang.Object ref = description_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); description_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } // repeated .TimelineAnnotation timeline = 8; public static final int TIMELINE_FIELD_NUMBER = 8; private java.util.List timeline_; /** * repeated .TimelineAnnotation timeline = 8; */ public java.util.List getTimelineList() { return timeline_; } /** * repeated .TimelineAnnotation timeline = 8; */ public java.util.List getTimelineOrBuilderList() { return timeline_; } /** * repeated .TimelineAnnotation timeline = 8; */ public int getTimelineCount() { return timeline_.size(); } /** * repeated .TimelineAnnotation timeline = 8; */ public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation getTimeline(int index) { return timeline_.get(index); } /** * repeated .TimelineAnnotation timeline = 8; */ public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotationOrBuilder getTimelineOrBuilder( int index) { return timeline_.get(index); } private void initFields() { traceId_ = 0L; parentId_ = 0L; start_ = 0L; stop_ = 0L; spanId_ = 0L; processId_ = ""; description_ = ""; timeline_ = java.util.Collections.emptyList(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized != -1) return isInitialized == 1; if (!hasTraceId()) { memoizedIsInitialized = 0; return false; } if (!hasParentId()) { memoizedIsInitialized = 0; return false; } if (!hasStart()) { memoizedIsInitialized = 0; return false; } if (!hasStop()) { memoizedIsInitialized = 0; return false; } if (!hasSpanId()) { memoizedIsInitialized = 0; return false; } if (!hasProcessId()) { memoizedIsInitialized = 0; return false; } if (!hasDescription()) { memoizedIsInitialized = 0; return false; } for (int i = 0; i < getTimelineCount(); i++) { if (!getTimeline(i).isInitialized()) { memoizedIsInitialized = 0; return false; } } memoizedIsInitialized = 1; return true; } public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); if (((bitField0_ & 0x00000001) == 0x00000001)) { output.writeInt64(1, traceId_); } if (((bitField0_ & 0x00000002) == 0x00000002)) { output.writeInt64(2, parentId_); } if (((bitField0_ & 0x00000004) == 0x00000004)) { output.writeInt64(3, start_); } if (((bitField0_ & 0x00000008) == 0x00000008)) { output.writeInt64(4, stop_); } if (((bitField0_ & 0x00000010) == 0x00000010)) { output.writeInt64(5, spanId_); } if (((bitField0_ & 0x00000020) == 0x00000020)) { output.writeBytes(6, getProcessIdBytes()); } if (((bitField0_ & 0x00000040) == 0x00000040)) { output.writeBytes(7, getDescriptionBytes()); } for (int i = 0; i < timeline_.size(); i++) { output.writeMessage(8, timeline_.get(i)); } getUnknownFields().writeTo(output); } private int memoizedSerializedSize = -1; public int getSerializedSize() { int size = memoizedSerializedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) == 0x00000001)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(1, traceId_); } if (((bitField0_ & 0x00000002) == 0x00000002)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(2, parentId_); } if (((bitField0_ & 0x00000004) == 0x00000004)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(3, start_); } if (((bitField0_ & 0x00000008) == 0x00000008)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(4, stop_); } if (((bitField0_ & 0x00000010) == 0x00000010)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(5, spanId_); } if (((bitField0_ & 0x00000020) == 0x00000020)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(6, getProcessIdBytes()); } if (((bitField0_ & 0x00000040) == 0x00000040)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(7, getDescriptionBytes()); } for (int i = 0; i < timeline_.size(); i++) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(8, timeline_.get(i)); } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; } private static final long serialVersionUID = 0L; @java.lang.Override protected java.lang.Object writeReplace() throws java.io.ObjectStreamException { return super.writeReplace(); } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.apache.htrace.protobuf.generated.SpanProtos.Span)) { return super.equals(obj); } org.apache.htrace.protobuf.generated.SpanProtos.Span other = (org.apache.htrace.protobuf.generated.SpanProtos.Span) obj; boolean result = true; result = result && (hasTraceId() == other.hasTraceId()); if (hasTraceId()) { result = result && (getTraceId() == other.getTraceId()); } result = result && (hasParentId() == other.hasParentId()); if (hasParentId()) { result = result && (getParentId() == other.getParentId()); } result = result && (hasStart() == other.hasStart()); if (hasStart()) { result = result && (getStart() == other.getStart()); } result = result && (hasStop() == other.hasStop()); if (hasStop()) { result = result && (getStop() == other.getStop()); } result = result && (hasSpanId() == other.hasSpanId()); if (hasSpanId()) { result = result && (getSpanId() == other.getSpanId()); } result = result && (hasProcessId() == other.hasProcessId()); if (hasProcessId()) { result = result && getProcessId() .equals(other.getProcessId()); } result = result && (hasDescription() == other.hasDescription()); if (hasDescription()) { result = result && getDescription() .equals(other.getDescription()); } result = result && getTimelineList() .equals(other.getTimelineList()); result = result && getUnknownFields().equals(other.getUnknownFields()); return result; } private int memoizedHashCode = 0; @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptorForType().hashCode(); if (hasTraceId()) { hash = (37 * hash) + TRACE_ID_FIELD_NUMBER; hash = (53 * hash) + hashLong(getTraceId()); } if (hasParentId()) { hash = (37 * hash) + PARENT_ID_FIELD_NUMBER; hash = (53 * hash) + hashLong(getParentId()); } if (hasStart()) { hash = (37 * hash) + START_FIELD_NUMBER; hash = (53 * hash) + hashLong(getStart()); } if (hasStop()) { hash = (37 * hash) + STOP_FIELD_NUMBER; hash = (53 * hash) + hashLong(getStop()); } if (hasSpanId()) { hash = (37 * hash) + SPAN_ID_FIELD_NUMBER; hash = (53 * hash) + hashLong(getSpanId()); } if (hasProcessId()) { hash = (37 * hash) + PROCESS_ID_FIELD_NUMBER; hash = (53 * hash) + getProcessId().hashCode(); } if (hasDescription()) { hash = (37 * hash) + DESCRIPTION_FIELD_NUMBER; hash = (53 * hash) + getDescription().hashCode(); } if (getTimelineCount() > 0) { hash = (37 * hash) + TIMELINE_FIELD_NUMBER; hash = (53 * hash) + getTimelineList().hashCode(); } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom(java.io.InputStream input) throws java.io.IOException { return PARSER.parseFrom(input); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseFrom(input, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return PARSER.parseDelimitedFrom(input); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseDelimitedFrom(input, extensionRegistry); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return PARSER.parseFrom(input); } public static org.apache.htrace.protobuf.generated.SpanProtos.Span parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return PARSER.parseFrom(input, extensionRegistry); } public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder(org.apache.htrace.protobuf.generated.SpanProtos.Span prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code Span} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements org.apache.htrace.protobuf.generated.SpanProtos.SpanOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_Span_descriptor; } protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_Span_fieldAccessorTable .ensureFieldAccessorsInitialized( org.apache.htrace.protobuf.generated.SpanProtos.Span.class, org.apache.htrace.protobuf.generated.SpanProtos.Span.Builder.class); } // Construct using org.apache.htrace.protobuf.generated.SpanProtos.Span.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { getTimelineFieldBuilder(); } } private static Builder create() { return new Builder(); } public Builder clear() { super.clear(); traceId_ = 0L; bitField0_ = (bitField0_ & ~0x00000001); parentId_ = 0L; bitField0_ = (bitField0_ & ~0x00000002); start_ = 0L; bitField0_ = (bitField0_ & ~0x00000004); stop_ = 0L; bitField0_ = (bitField0_ & ~0x00000008); spanId_ = 0L; bitField0_ = (bitField0_ & ~0x00000010); processId_ = ""; bitField0_ = (bitField0_ & ~0x00000020); description_ = ""; bitField0_ = (bitField0_ & ~0x00000040); if (timelineBuilder_ == null) { timeline_ = java.util.Collections.emptyList(); bitField0_ = (bitField0_ & ~0x00000080); } else { timelineBuilder_.clear(); } return this; } public Builder clone() { return create().mergeFrom(buildPartial()); } public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.apache.htrace.protobuf.generated.SpanProtos.internal_static_Span_descriptor; } public org.apache.htrace.protobuf.generated.SpanProtos.Span getDefaultInstanceForType() { return org.apache.htrace.protobuf.generated.SpanProtos.Span.getDefaultInstance(); } public org.apache.htrace.protobuf.generated.SpanProtos.Span build() { org.apache.htrace.protobuf.generated.SpanProtos.Span result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } public org.apache.htrace.protobuf.generated.SpanProtos.Span buildPartial() { org.apache.htrace.protobuf.generated.SpanProtos.Span result = new org.apache.htrace.protobuf.generated.SpanProtos.Span(this); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { to_bitField0_ |= 0x00000001; } result.traceId_ = traceId_; if (((from_bitField0_ & 0x00000002) == 0x00000002)) { to_bitField0_ |= 0x00000002; } result.parentId_ = parentId_; if (((from_bitField0_ & 0x00000004) == 0x00000004)) { to_bitField0_ |= 0x00000004; } result.start_ = start_; if (((from_bitField0_ & 0x00000008) == 0x00000008)) { to_bitField0_ |= 0x00000008; } result.stop_ = stop_; if (((from_bitField0_ & 0x00000010) == 0x00000010)) { to_bitField0_ |= 0x00000010; } result.spanId_ = spanId_; if (((from_bitField0_ & 0x00000020) == 0x00000020)) { to_bitField0_ |= 0x00000020; } result.processId_ = processId_; if (((from_bitField0_ & 0x00000040) == 0x00000040)) { to_bitField0_ |= 0x00000040; } result.description_ = description_; if (timelineBuilder_ == null) { if (((bitField0_ & 0x00000080) == 0x00000080)) { timeline_ = java.util.Collections.unmodifiableList(timeline_); bitField0_ = (bitField0_ & ~0x00000080); } result.timeline_ = timeline_; } else { result.timeline_ = timelineBuilder_.build(); } result.bitField0_ = to_bitField0_; onBuilt(); return result; } public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.apache.htrace.protobuf.generated.SpanProtos.Span) { return mergeFrom((org.apache.htrace.protobuf.generated.SpanProtos.Span)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.apache.htrace.protobuf.generated.SpanProtos.Span other) { if (other == org.apache.htrace.protobuf.generated.SpanProtos.Span.getDefaultInstance()) return this; if (other.hasTraceId()) { setTraceId(other.getTraceId()); } if (other.hasParentId()) { setParentId(other.getParentId()); } if (other.hasStart()) { setStart(other.getStart()); } if (other.hasStop()) { setStop(other.getStop()); } if (other.hasSpanId()) { setSpanId(other.getSpanId()); } if (other.hasProcessId()) { bitField0_ |= 0x00000020; processId_ = other.processId_; onChanged(); } if (other.hasDescription()) { bitField0_ |= 0x00000040; description_ = other.description_; onChanged(); } if (timelineBuilder_ == null) { if (!other.timeline_.isEmpty()) { if (timeline_.isEmpty()) { timeline_ = other.timeline_; bitField0_ = (bitField0_ & ~0x00000080); } else { ensureTimelineIsMutable(); timeline_.addAll(other.timeline_); } onChanged(); } } else { if (!other.timeline_.isEmpty()) { if (timelineBuilder_.isEmpty()) { timelineBuilder_.dispose(); timelineBuilder_ = null; timeline_ = other.timeline_; bitField0_ = (bitField0_ & ~0x00000080); timelineBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getTimelineFieldBuilder() : null; } else { timelineBuilder_.addAllMessages(other.timeline_); } } } this.mergeUnknownFields(other.getUnknownFields()); return this; } public final boolean isInitialized() { if (!hasTraceId()) { return false; } if (!hasParentId()) { return false; } if (!hasStart()) { return false; } if (!hasStop()) { return false; } if (!hasSpanId()) { return false; } if (!hasProcessId()) { return false; } if (!hasDescription()) { return false; } for (int i = 0; i < getTimelineCount(); i++) { if (!getTimeline(i).isInitialized()) { return false; } } return true; } public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { org.apache.htrace.protobuf.generated.SpanProtos.Span parsedMessage = null; try { parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { parsedMessage = (org.apache.htrace.protobuf.generated.SpanProtos.Span) e.getUnfinishedMessage(); throw e; } finally { if (parsedMessage != null) { mergeFrom(parsedMessage); } } return this; } private int bitField0_; // required int64 trace_id = 1; private long traceId_ ; /** * required int64 trace_id = 1; */ public boolean hasTraceId() { return ((bitField0_ & 0x00000001) == 0x00000001); } /** * required int64 trace_id = 1; */ public long getTraceId() { return traceId_; } /** * required int64 trace_id = 1; */ public Builder setTraceId(long value) { bitField0_ |= 0x00000001; traceId_ = value; onChanged(); return this; } /** * required int64 trace_id = 1; */ public Builder clearTraceId() { bitField0_ = (bitField0_ & ~0x00000001); traceId_ = 0L; onChanged(); return this; } // required int64 parent_id = 2; private long parentId_ ; /** * required int64 parent_id = 2; */ public boolean hasParentId() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** * required int64 parent_id = 2; */ public long getParentId() { return parentId_; } /** * required int64 parent_id = 2; */ public Builder setParentId(long value) { bitField0_ |= 0x00000002; parentId_ = value; onChanged(); return this; } /** * required int64 parent_id = 2; */ public Builder clearParentId() { bitField0_ = (bitField0_ & ~0x00000002); parentId_ = 0L; onChanged(); return this; } // required int64 start = 3; private long start_ ; /** * required int64 start = 3; */ public boolean hasStart() { return ((bitField0_ & 0x00000004) == 0x00000004); } /** * required int64 start = 3; */ public long getStart() { return start_; } /** * required int64 start = 3; */ public Builder setStart(long value) { bitField0_ |= 0x00000004; start_ = value; onChanged(); return this; } /** * required int64 start = 3; */ public Builder clearStart() { bitField0_ = (bitField0_ & ~0x00000004); start_ = 0L; onChanged(); return this; } // required int64 stop = 4; private long stop_ ; /** * required int64 stop = 4; */ public boolean hasStop() { return ((bitField0_ & 0x00000008) == 0x00000008); } /** * required int64 stop = 4; */ public long getStop() { return stop_; } /** * required int64 stop = 4; */ public Builder setStop(long value) { bitField0_ |= 0x00000008; stop_ = value; onChanged(); return this; } /** * required int64 stop = 4; */ public Builder clearStop() { bitField0_ = (bitField0_ & ~0x00000008); stop_ = 0L; onChanged(); return this; } // required int64 span_id = 5; private long spanId_ ; /** * required int64 span_id = 5; */ public boolean hasSpanId() { return ((bitField0_ & 0x00000010) == 0x00000010); } /** * required int64 span_id = 5; */ public long getSpanId() { return spanId_; } /** * required int64 span_id = 5; */ public Builder setSpanId(long value) { bitField0_ |= 0x00000010; spanId_ = value; onChanged(); return this; } /** * required int64 span_id = 5; */ public Builder clearSpanId() { bitField0_ = (bitField0_ & ~0x00000010); spanId_ = 0L; onChanged(); return this; } // required string process_id = 6; private java.lang.Object processId_ = ""; /** * required string process_id = 6; */ public boolean hasProcessId() { return ((bitField0_ & 0x00000020) == 0x00000020); } /** * required string process_id = 6; */ public java.lang.String getProcessId() { java.lang.Object ref = processId_; if (!(ref instanceof java.lang.String)) { java.lang.String s = ((com.google.protobuf.ByteString) ref) .toStringUtf8(); processId_ = s; return s; } else { return (java.lang.String) ref; } } /** * required string process_id = 6; */ public com.google.protobuf.ByteString getProcessIdBytes() { java.lang.Object ref = processId_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); processId_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * required string process_id = 6; */ public Builder setProcessId( java.lang.String value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000020; processId_ = value; onChanged(); return this; } /** * required string process_id = 6; */ public Builder clearProcessId() { bitField0_ = (bitField0_ & ~0x00000020); processId_ = getDefaultInstance().getProcessId(); onChanged(); return this; } /** * required string process_id = 6; */ public Builder setProcessIdBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000020; processId_ = value; onChanged(); return this; } // required string description = 7; private java.lang.Object description_ = ""; /** * required string description = 7; */ public boolean hasDescription() { return ((bitField0_ & 0x00000040) == 0x00000040); } /** * required string description = 7; */ public java.lang.String getDescription() { java.lang.Object ref = description_; if (!(ref instanceof java.lang.String)) { java.lang.String s = ((com.google.protobuf.ByteString) ref) .toStringUtf8(); description_ = s; return s; } else { return (java.lang.String) ref; } } /** * required string description = 7; */ public com.google.protobuf.ByteString getDescriptionBytes() { java.lang.Object ref = description_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); description_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * required string description = 7; */ public Builder setDescription( java.lang.String value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000040; description_ = value; onChanged(); return this; } /** * required string description = 7; */ public Builder clearDescription() { bitField0_ = (bitField0_ & ~0x00000040); description_ = getDefaultInstance().getDescription(); onChanged(); return this; } /** * required string description = 7; */ public Builder setDescriptionBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000040; description_ = value; onChanged(); return this; } // repeated .TimelineAnnotation timeline = 8; private java.util.List timeline_ = java.util.Collections.emptyList(); private void ensureTimelineIsMutable() { if (!((bitField0_ & 0x00000080) == 0x00000080)) { timeline_ = new java.util.ArrayList(timeline_); bitField0_ |= 0x00000080; } } private com.google.protobuf.RepeatedFieldBuilder< org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotationOrBuilder> timelineBuilder_; /** * repeated .TimelineAnnotation timeline = 8; */ public java.util.List getTimelineList() { if (timelineBuilder_ == null) { return java.util.Collections.unmodifiableList(timeline_); } else { return timelineBuilder_.getMessageList(); } } /** * repeated .TimelineAnnotation timeline = 8; */ public int getTimelineCount() { if (timelineBuilder_ == null) { return timeline_.size(); } else { return timelineBuilder_.getCount(); } } /** * repeated .TimelineAnnotation timeline = 8; */ public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation getTimeline(int index) { if (timelineBuilder_ == null) { return timeline_.get(index); } else { return timelineBuilder_.getMessage(index); } } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder setTimeline( int index, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation value) { if (timelineBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureTimelineIsMutable(); timeline_.set(index, value); onChanged(); } else { timelineBuilder_.setMessage(index, value); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder setTimeline( int index, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder builderForValue) { if (timelineBuilder_ == null) { ensureTimelineIsMutable(); timeline_.set(index, builderForValue.build()); onChanged(); } else { timelineBuilder_.setMessage(index, builderForValue.build()); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder addTimeline(org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation value) { if (timelineBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureTimelineIsMutable(); timeline_.add(value); onChanged(); } else { timelineBuilder_.addMessage(value); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder addTimeline( int index, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation value) { if (timelineBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureTimelineIsMutable(); timeline_.add(index, value); onChanged(); } else { timelineBuilder_.addMessage(index, value); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder addTimeline( org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder builderForValue) { if (timelineBuilder_ == null) { ensureTimelineIsMutable(); timeline_.add(builderForValue.build()); onChanged(); } else { timelineBuilder_.addMessage(builderForValue.build()); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder addTimeline( int index, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder builderForValue) { if (timelineBuilder_ == null) { ensureTimelineIsMutable(); timeline_.add(index, builderForValue.build()); onChanged(); } else { timelineBuilder_.addMessage(index, builderForValue.build()); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder addAllTimeline( java.lang.Iterable values) { if (timelineBuilder_ == null) { ensureTimelineIsMutable(); super.addAll(values, timeline_); onChanged(); } else { timelineBuilder_.addAllMessages(values); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder clearTimeline() { if (timelineBuilder_ == null) { timeline_ = java.util.Collections.emptyList(); bitField0_ = (bitField0_ & ~0x00000080); onChanged(); } else { timelineBuilder_.clear(); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public Builder removeTimeline(int index) { if (timelineBuilder_ == null) { ensureTimelineIsMutable(); timeline_.remove(index); onChanged(); } else { timelineBuilder_.remove(index); } return this; } /** * repeated .TimelineAnnotation timeline = 8; */ public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder getTimelineBuilder( int index) { return getTimelineFieldBuilder().getBuilder(index); } /** * repeated .TimelineAnnotation timeline = 8; */ public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotationOrBuilder getTimelineOrBuilder( int index) { if (timelineBuilder_ == null) { return timeline_.get(index); } else { return timelineBuilder_.getMessageOrBuilder(index); } } /** * repeated .TimelineAnnotation timeline = 8; */ public java.util.List getTimelineOrBuilderList() { if (timelineBuilder_ != null) { return timelineBuilder_.getMessageOrBuilderList(); } else { return java.util.Collections.unmodifiableList(timeline_); } } /** * repeated .TimelineAnnotation timeline = 8; */ public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder addTimelineBuilder() { return getTimelineFieldBuilder().addBuilder( org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.getDefaultInstance()); } /** * repeated .TimelineAnnotation timeline = 8; */ public org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder addTimelineBuilder( int index) { return getTimelineFieldBuilder().addBuilder( index, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.getDefaultInstance()); } /** * repeated .TimelineAnnotation timeline = 8; */ public java.util.List getTimelineBuilderList() { return getTimelineFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotationOrBuilder> getTimelineFieldBuilder() { if (timelineBuilder_ == null) { timelineBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation.Builder, org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotationOrBuilder>( timeline_, ((bitField0_ & 0x00000080) == 0x00000080), getParentForChildren(), isClean()); timeline_ = null; } return timelineBuilder_; } // @@protoc_insertion_point(builder_scope:Span) } static { defaultInstance = new Span(true); defaultInstance.initFields(); } // @@protoc_insertion_point(class_scope:Span) } private static com.google.protobuf.Descriptors.Descriptor internal_static_TimelineAnnotation_descriptor; private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_TimelineAnnotation_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_Span_descriptor; private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_Span_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; } private static com.google.protobuf.Descriptors.FileDescriptor descriptor; static { java.lang.String[] descriptorData = { "\n\nSpan.proto\"3\n\022TimelineAnnotation\022\014\n\004ti" + "me\030\001 \002(\003\022\017\n\007message\030\002 \002(\t\"\251\001\n\004Span\022\020\n\010tr" + "ace_id\030\001 \002(\003\022\021\n\tparent_id\030\002 \002(\003\022\r\n\005start" + "\030\003 \002(\003\022\014\n\004stop\030\004 \002(\003\022\017\n\007span_id\030\005 \002(\003\022\022\n" + "\nprocess_id\030\006 \002(\t\022\023\n\013description\030\007 \002(\t\022%" + "\n\010timeline\030\010 \003(\0132\023.TimelineAnnotationB0\n" + "\035org.htrace.protobuf.generatedB\nSpanProt" + "osH\001\240\001\001" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.Descriptors.FileDescriptor root) { descriptor = root; internal_static_TimelineAnnotation_descriptor = getDescriptor().getMessageTypes().get(0); internal_static_TimelineAnnotation_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_TimelineAnnotation_descriptor, new java.lang.String[] { "Time", "Message", }); internal_static_Span_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_Span_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_Span_descriptor, new java.lang.String[] { "TraceId", "ParentId", "Start", "Stop", "SpanId", "ProcessId", "Description", "Timeline", }); return null; } }; com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] { }, assigner); } // @@protoc_insertion_point(outer_class_scope) } incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/viewer/000077500000000000000000000000001245601110500265015ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/viewer/HBaseSpanViewer.java000066400000000000000000000172441245601110500323420ustar00rootroot00000000000000/* * 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 org.apache.htrace.viewer; import com.google.protobuf.Message; import com.google.protobuf.Descriptors.FieldDescriptor; import java.io.InputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HConnection; import org.apache.hadoop.hbase.client.HConnectionManager; import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; import org.apache.htrace.impl.HBaseSpanReceiver; import org.apache.htrace.protobuf.generated.SpanProtos; public class HBaseSpanViewer { private static final Log LOG = LogFactory.getLog(HBaseSpanViewer.class); private Configuration conf; private HConnection hconnection; private HTableInterface htable; private byte[] table; private byte[] cf; private byte[] icf; public HBaseSpanViewer(Configuration conf) { this.conf = conf; this.table = Bytes.toBytes(conf.get(HBaseSpanReceiver.TABLE_KEY, HBaseSpanReceiver.DEFAULT_TABLE)); this.cf = Bytes.toBytes(conf.get(HBaseSpanReceiver.COLUMNFAMILY_KEY, HBaseSpanReceiver.DEFAULT_COLUMNFAMILY)); this.icf = Bytes.toBytes(conf.get(HBaseSpanReceiver.INDEXFAMILY_KEY, HBaseSpanReceiver.DEFAULT_INDEXFAMILY)); } public void close() { stopClient(); } public void startClient() { if (this.htable == null) { try { this.hconnection = HConnectionManager.createConnection(conf); this.htable = hconnection.getTable(table); } catch (IOException e) { LOG.warn("Failed to create HBase connection. " + e.getMessage()); } } } public void stopClient() { try { if (this.htable != null) { this.htable.close(); this.htable = null; } if (this.hconnection != null) { this.hconnection.close(); this.hconnection = null; } } catch (IOException e) { LOG.warn("Failed to close HBase connection. " + e.getMessage()); } } public List getSpans(long traceid) throws IOException { startClient(); List spans = new ArrayList(); Get get = new Get(Bytes.toBytes(traceid)); get.addFamily(this.cf); try { for (Cell cell : htable.get(get).listCells()) { InputStream in = new ByteArrayInputStream(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); spans.add(SpanProtos.Span.parseFrom(in)); } } catch (IOException e) { LOG.warn("Failed to get spans from HBase. " + e.getMessage()); stopClient(); } return spans; } public List getRootSpans() throws IOException { startClient(); Scan scan = new Scan(); scan.addColumn(this.icf, HBaseSpanReceiver.INDEX_SPAN_QUAL); List spans = new ArrayList(); try { ResultScanner scanner = htable.getScanner(scan); Result result = null; while ((result = scanner.next()) != null) { for (Cell cell : result.listCells()) { InputStream in = new ByteArrayInputStream(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); spans.add(SpanProtos.Span.parseFrom(in)); } } } catch (IOException e) { LOG.warn("Failed to get root spans from HBase. " + e.getMessage()); stopClient(); } return spans; } public static String toJsonString(final Message message) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(out, Charset.defaultCharset()); appendJsonString(message, writer); writer.flush(); out.flush(); return out.toString(); } public static void appendJsonString(final Message message, OutputStreamWriter writer) throws IOException { writer.append("{"); for (Iterator> iter = message.getAllFields().entrySet().iterator(); iter.hasNext();) { Map.Entry field = iter.next(); appendFields(field.getKey(), field.getValue(), writer); if (iter.hasNext()) { writer.append(","); } } writer.append("}"); } private static void appendFields(FieldDescriptor fd, Object value, OutputStreamWriter writer) throws IOException { writer.append("\""); writer.append(fd.getName()); writer.append("\""); writer.append(":"); if (fd.isRepeated()) { writer.append("["); for (Iterator it = ((List) value).iterator(); it.hasNext();) { appendValue(fd, it.next(), writer); if (it.hasNext()) { writer.append(","); } } writer.append("]"); } else { appendValue(fd, value, writer); } } private static void appendValue(FieldDescriptor fd, Object value, OutputStreamWriter writer) throws IOException { switch (fd.getType()) { case INT64: // write int as string for handling in javascript case STRING: writer.append("\""); writer.append(value.toString()); writer.append("\""); break; case MESSAGE: appendJsonString((Message)value, writer); break; default: throw new IOException("unexpected field type."); } } /** * Run basic test. * @throws IOException */ public static void main(String[] args) throws IOException { HBaseSpanViewer viewer = new HBaseSpanViewer(HBaseConfiguration.create()); if (args.length == 0) { List spans = viewer.getRootSpans(); for (SpanProtos.Span span : spans) { System.out.println(toJsonString(span)); } } else { List spans = viewer.getSpans(Long.parseLong(args[0])); for (SpanProtos.Span span : spans) { System.out.println(toJsonString(span)); } } viewer.close(); } } HBaseSpanViewerServer.java000066400000000000000000000076121245601110500334500ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/viewer/* * 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 org.apache.htrace.viewer; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.http.HttpServer2; import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import org.apache.hadoop.hbase.HBaseConfiguration; public class HBaseSpanViewerServer implements Tool { private static final Log LOG = LogFactory.getLog(HBaseSpanViewerServer.class); public static final String HTRACE_VIEWER_HTTP_ADDRESS_KEY = "htrace.viewer.http.address"; public static final String HTRACE_VIEWER_HTTP_ADDRESS_DEFAULT = "0.0.0.0:16900"; public static final String HTRACE_CONF_ATTR = "htrace.conf"; public static final String HTRACE_APPDIR = "webapps"; public static final String NAME = "htrace"; private Configuration conf; private HttpServer2 httpServer; private InetSocketAddress httpAddress; public void setConf(Configuration conf) { this.conf = conf; } public Configuration getConf() { return this.conf; } void start() throws IOException { httpAddress = NetUtils.createSocketAddr( conf.get(HTRACE_VIEWER_HTTP_ADDRESS_KEY, HTRACE_VIEWER_HTTP_ADDRESS_DEFAULT)); conf.set(HTRACE_VIEWER_HTTP_ADDRESS_KEY, NetUtils.getHostPortString(httpAddress)); HttpServer2.Builder builder = new HttpServer2.Builder(); builder.setName(NAME).setConf(conf); if (httpAddress.getPort() == 0) { builder.setFindPort(true); } URI uri = URI.create("http://" + NetUtils.getHostPortString(httpAddress)); builder.addEndpoint(uri); LOG.info("Starting Web-server for " + NAME + " at: " + uri); httpServer = builder.build(); httpServer.setAttribute(HTRACE_CONF_ATTR, conf); httpServer.addServlet("gettraces", HBaseSpanViewerTracesServlet.PREFIX, HBaseSpanViewerTracesServlet.class); httpServer.addServlet("getspans", HBaseSpanViewerSpansServlet.PREFIX + "/*", HBaseSpanViewerSpansServlet.class); // for webapps/htrace bundled in jar. String rb = httpServer.getClass() .getClassLoader() .getResource("webapps/" + NAME) .toString(); httpServer.getWebAppContext().setResourceBase(rb); httpServer.start(); httpAddress = httpServer.getConnectorAddress(0); } void join() throws Exception { if (httpServer != null) { httpServer.join(); } } void stop() throws Exception { if (httpServer != null) { httpServer.stop(); } } InetSocketAddress getHttpAddress() { return httpAddress; } public int run(String[] args) throws Exception { start(); join(); stop(); return 0; } /** * @throws IOException */ public static void main(String[] args) throws Exception { ToolRunner.run(HBaseConfiguration.create(), new HBaseSpanViewerServer(), args); } } HBaseSpanViewerSpansServlet.java000066400000000000000000000062511245601110500346310ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/viewer/* * 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 org.apache.htrace.viewer; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.util.ServletUtil; import org.apache.htrace.protobuf.generated.SpanProtos; public class HBaseSpanViewerSpansServlet extends HttpServlet { private static final Log LOG = LogFactory.getLog(HBaseSpanViewerSpansServlet.class); public static final String PREFIX = "/getspans"; private static final ThreadLocal tlviewer = new ThreadLocal() { @Override protected HBaseSpanViewer initialValue() { return null; } }; @Override @SuppressWarnings("unchecked") public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { final String path = validatePath(ServletUtil.getDecodedPath(request, PREFIX)); if (path == null) { response.setContentType("text/plain"); response.getWriter().print("Invalid input"); return; } HBaseSpanViewer viewer = tlviewer.get(); if (viewer == null) { final Configuration conf = (Configuration) getServletContext() .getAttribute(HBaseSpanViewerServer.HTRACE_CONF_ATTR); viewer = new HBaseSpanViewer(conf); tlviewer.set(viewer); } Long traceid = Long.parseLong(path.substring(1)); response.setContentType("application/javascript"); PrintWriter out = response.getWriter(); out.print("["); boolean first = true; for (SpanProtos.Span span : viewer.getSpans(traceid)) { if (first) { first = false; } else { out.print(","); } out.print(HBaseSpanViewer.toJsonString(span)); } out.print("]"); } @Override public void init() throws ServletException { } @Override public void destroy() { HBaseSpanViewer viewer = tlviewer.get(); if (viewer != null) { viewer.close(); } } public static String validatePath(String p) { return p == null || p.length() == 0? null: new Path(p).toUri().getPath(); } } HBaseSpanViewerTracesServlet.java000066400000000000000000000054031245601110500347640ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/java/org/apache/htrace/viewer/* * 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 org.apache.htrace.viewer; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.util.ServletUtil; import org.apache.htrace.protobuf.generated.SpanProtos; public class HBaseSpanViewerTracesServlet extends HttpServlet { private static final Log LOG = LogFactory.getLog(HBaseSpanViewerTracesServlet.class); public static final String PREFIX = "/gettraces"; private static final ThreadLocal tlviewer = new ThreadLocal() { @Override protected HBaseSpanViewer initialValue() { return null; } }; @Override @SuppressWarnings("unchecked") public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HBaseSpanViewer viewer = tlviewer.get(); if (viewer == null) { final Configuration conf = (Configuration) getServletContext() .getAttribute(HBaseSpanViewerServer.HTRACE_CONF_ATTR); viewer = new HBaseSpanViewer(conf); tlviewer.set(viewer); } response.setContentType("application/javascript"); PrintWriter out = response.getWriter(); out.print("["); boolean first = true; for (SpanProtos.Span span : viewer.getRootSpans()) { if (first) { first = false; } else { out.print(","); } out.print(HBaseSpanViewer.toJsonString(span)); } out.print("]"); } @Override public void init() throws ServletException { } @Override public void destroy() { HBaseSpanViewer viewer = tlviewer.get(); if (viewer != null) { viewer.close(); } } } incubator-htrace-3.1.0/htrace-hbase/src/main/protobuf/000077500000000000000000000000001245601110500226415ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/protobuf/Span.proto000066400000000000000000000025151245601110500246320ustar00rootroot00000000000000/** * 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. */ option java_package = "org.apache.htrace.protobuf.generated"; option java_outer_classname = "SpanProtos"; option java_generate_equals_and_hash = true; option optimize_for = SPEED; message TimelineAnnotation { required int64 time = 1; required string message = 2; } message Span { required int64 trace_id = 1; required int64 parent_id = 2; required int64 start = 3; required int64 stop = 4; required int64 span_id = 5; required string process_id = 6; required string description = 7; repeated TimelineAnnotation timeline = 8; } incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/000077500000000000000000000000001245601110500224425ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/000077500000000000000000000000001245601110500237105ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/WEB-INF/000077500000000000000000000000001245601110500247375ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/WEB-INF/web.xml000066400000000000000000000012251245601110500262360ustar00rootroot00000000000000 incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/index.html000066400000000000000000000020541245601110500257060ustar00rootroot00000000000000 HTrace Viewer incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/spans.html000066400000000000000000000023311245601110500257210ustar00rootroot00000000000000 incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/spans.js000066400000000000000000000132571245601110500254020ustar00rootroot00000000000000/** * 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. */ const height_span = 20; const width_span = 700; const size_tl = 6; const margin = {top: 50, bottom: 50, left: 50, right: 1000, process: 250}; const ROOT_SPAN_ID = "477902"; // constants defined in org.apache.htrace.Span const traceid = window.location.search.substring(1).split("=")[1]; d3.json("/getspans/" + traceid, function(spans) { spans.map(function(s) { s.start = parseInt(s.start); s.stop = parseInt(s.stop); if (s.timeline) { s.timeline.forEach(function(t) { t.time = parseInt(t.time); }); } }); var byparent = d3.nest() .sortValues(function(a, b) { return a.start < b.start ? -1 : a.start > b.start ? 1 : 0; }) .key(function(e) { return e.parent_id; }) .map(spans, d3.map); addchildren(byparent.get(ROOT_SPAN_ID), byparent); var sortedspans = []; traverse(0, byparent.get(ROOT_SPAN_ID), function(e) { sortedspans.push(e); }); var height_screen = spans.length * height_span; var tmin = d3.min(spans, function(s) { return s.start; }); var tmax = d3.max(spans, function(s) { return s.stop; }); var xscale = d3.time.scale() .domain([new Date(tmin), new Date(tmax)]).range([0, width_span]); var svg = d3.select("body").append("svg") .attr("width", width_span + margin.process + margin.left + margin.right) .attr("height", height_screen + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var bars = svg.append("g") .attr("id", "bars") .attr("width", width_span) .attr("height", height_screen) .attr("transform", "translate(" + margin.process + ", 0)"); var span_g = bars.selectAll("g.span") .data(sortedspans) .enter() .append("g") .attr("transform", function(s, i) { return "translate(0, " + (i * height_span + 5) + ")"; }) .classed("timeline", function(d) { return d.timeline; }); span_g.append("text") .text(function(s) { return s.process_id; }) .style("alignment-baseline", "hanging") .attr("transform", function(s) { return "translate(" + (s.depth * 10 - margin.process) + ", 0)"; }); var rect_g = span_g.append("g") .attr("transform", function(s) { return "translate(" + xscale(new Date(s.start)) + ", 0)"; }); rect_g.append("rect") .attr("height", height_span - 1) .attr("width", function (s) { return (width_span * (s.stop - s.start)) / (tmax - tmin) + 1; }) .style("fill", "lightblue") .attr("class", "span") rect_g.append("text") .text(function(s){ return s.description; }) .style("alignment-baseline", "hanging"); rect_g.append("text") .text(function(s){ return s.stop - s.start; }) .style("alignment-baseline", "baseline") .style("text-anchor", "end") .style("font-size", "10px") .attr("transform", function(s, i) { return "translate(0, 10)"; }); bars.selectAll("g.timeline").selectAll("rect.timeline") .data(function(s) { return s.timeline; }) .enter() .append("rect") .style("fill", "red") .attr("height", size_tl) .attr("width", size_tl) .attr("transform", function(t) { return "translate(" + xscale(t.time) + "," + (height_span - 1 - size_tl) + ")"; }) .classed("timeline"); var popup = d3.select("body").append("div") .attr("class", "popup") .style("opacity", 0); bars.selectAll("g.timeline") .on("mouseover", function(d) { popup.transition().duration(300).style("opacity", .95); var text = ""; d.timeline.forEach(function (t) { text += ""; text += ""; }); text += "
" + (t.time - tmin) + " : " + t.message + "
" popup.html(text) .style("left", (document.body.scrollLeft + 30) + "px") .style("top", (document.body.scrollTop + 30) + "px") .style("width", "700px") .style("background", "orange") .style("position", "absolute"); }) .on("mouseout", function(d) { popup.transition().duration(300).style("opacity", 0); }); var axis = d3.svg.axis() .scale(xscale) .orient("top") .tickValues(xscale.domain()) .tickFormat(d3.time.format("%x %X.%L")) .tickSize(6, 3); bars.append("g").attr("class", "axis").call(axis); }); function addchildren(nodes, byparent) { nodes.forEach(function(e) { if (byparent.get(e.span_id)) { e.children = byparent.get(e.span_id); addchildren(e.children, byparent); } }); } function traverse(depth, children, func) { children.forEach(function(e) { e.depth = depth; func(e); if (e.children) { traverse (depth + 1, e.children, func); } }); } incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/traces.html000066400000000000000000000023321245601110500260570ustar00rootroot00000000000000 incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/htrace/traces.js000066400000000000000000000037751245601110500255430ustar00rootroot00000000000000/** * 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. */ d3.json("/gettraces", function(spans) { spans.map(function(s) { s.start = parseInt(s.start); s.stop = parseInt(s.stop); }); var table = d3.select("body") .append("table") .attr("style", "white-space: nowrap;") .attr("class", "table table-condensed"); var thead = table.append("thead"); var tbody = table.append("tbody"); var columns = ["start", "process_id", "description"]; thead.append("tr") .selectAll("th") .data(columns) .enter() .append("th") .html(function(d) { return d; }); var rows = tbody.selectAll("tr") .data(spans) .enter() .append("tr") .sort(function(a, b) { return a.start > b.start ? -1 : a.start < b.start ? 1 : 0; }) .attr("onclick", function(d) { return "window.location='spans.html?traceid=" + d.trace_id + "'"; }); rows.selectAll("td") .data(function(s) { return columns.map(function(c) { return s[c]; }); }) .enter() .append("td") .html(function(d) { return d; }); rows.select("td") .html(function(d) { return d3.time.format("%x %X.%L")(new Date(d.start)); }); }); incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/static/000077500000000000000000000000001245601110500237315ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/static/bootstrap-theme.min.css000077500000000000000000000355641245601110500303620ustar00rootroot00000000000000/*! * Bootstrap v3.0.0 * * Copyright 2013 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world by @mdo and @fat. */ .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,0%,#e6e6e6,100%);background-image:-moz-linear-gradient(top,#fff 0,#e6e6e6 100%);background-image:linear-gradient(to bottom,#fff 0,#e6e6e6 100%);background-repeat:repeat-x;border-color:#e0e0e0;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0)}.btn-default:active,.btn-default.active{background-color:#e6e6e6;border-color:#e0e0e0}.btn-primary{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca,0%,#3071a9,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;border-color:#2d6ca2;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.btn-primary:active,.btn-primary.active{background-color:#3071a9;border-color:#2d6ca2}.btn-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c,0%,#449d44,100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;border-color:#419641;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.btn-success:active,.btn-success.active{background-color:#449d44;border-color:#419641}.btn-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e,0%,#ec971f,100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;border-color:#eb9316;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.btn-warning:active,.btn-warning.active{background-color:#ec971f;border-color:#eb9316}.btn-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f,0%,#c9302c,100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;border-color:#c12e2a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.btn-danger:active,.btn-danger.active{background-color:#c9302c;border-color:#c12e2a}.btn-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de,0%,#31b0d5,100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;border-color:#2aabd2;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.btn-info:active,.btn-info.active{background-color:#31b0d5;border-color:#2aabd2}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca,0%,#357ebd,100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#f8f8f8));background-image:-webkit-linear-gradient(top,#fff,0%,#f8f8f8,100%);background-image:-moz-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar .navbar-nav>.active>a{background-color:#f8f8f8}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-gradient(linear,left 0,left 100%,from(#3c3c3c),to(#222));background-image:-webkit-linear-gradient(top,#3c3c3c,0%,#222,100%);background-image:-moz-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0)}.navbar-inverse .navbar-nav>.active>a{background-color:#222}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#c8e5bc));background-image:-webkit-linear-gradient(top,#dff0d8,0%,#c8e5bc,100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#b9def0));background-image:-webkit-linear-gradient(top,#d9edf7,0%,#b9def0,100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#f8efc0));background-image:-webkit-linear-gradient(top,#fcf8e3,0%,#f8efc0,100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#e7c3c3));background-image:-webkit-linear-gradient(top,#f2dede,0%,#e7c3c3,100%);background-image:-moz-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#ebebeb,0%,#f5f5f5,100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca,0%,#3071a9,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c,0%,#449d44,100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de,0%,#31b0d5,100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e,0%,#ec971f,100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f,0%,#c9302c,100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3278b3));background-image:-webkit-linear-gradient(top,#428bca,0%,#3278b3,100%);background-image:-moz-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5,0%,#e8e8e8,100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca,0%,#357ebd,100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#d0e9c6));background-image:-webkit-linear-gradient(top,#dff0d8,0%,#d0e9c6,100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#c4e3f3));background-image:-webkit-linear-gradient(top,#d9edf7,0%,#c4e3f3,100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#faf2cc));background-image:-webkit-linear-gradient(top,#fcf8e3,0%,#faf2cc,100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#ebcccc));background-image:-webkit-linear-gradient(top,#f2dede,0%,#ebcccc,100%);background-image:-moz-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-gradient(linear,left 0,left 100%,from(#e8e8e8),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#e8e8e8,0%,#f5f5f5,100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)}incubator-htrace-3.1.0/htrace-hbase/src/main/webapps/static/bootstrap.min.css000077500000000000000000002760731245601110500272640ustar00rootroot00000000000000/*! * Bootstrap v3.0.0 * * Copyright 2013 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world by @mdo and @fat. *//*! normalize.css v2.1.0 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}button,input,select[multiple],textarea{background-image:none}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16.099999999999998px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-warning{color:#c09853}.text-danger{color:#b94a48}.text-success{color:#468847}.text-info{color:#3a87ad}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h4,h5,h6{margin-top:10px;margin-bottom:10px}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}h1 small,.h1 small{font-size:24px}h2 small,.h2 small{font-size:18px}h3 small,.h3 small,h4 small,.h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:1.428571429}code,pre{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-1{width:8.333333333333332%}.col-xs-2{width:16.666666666666664%}.col-xs-3{width:25%}.col-xs-4{width:33.33333333333333%}.col-xs-5{width:41.66666666666667%}.col-xs-6{width:50%}.col-xs-7{width:58.333333333333336%}.col-xs-8{width:66.66666666666666%}.col-xs-9{width:75%}.col-xs-10{width:83.33333333333334%}.col-xs-11{width:91.66666666666666%}.col-xs-12{width:100%}@media(min-width:768px){.container{max-width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-1{width:8.333333333333332%}.col-sm-2{width:16.666666666666664%}.col-sm-3{width:25%}.col-sm-4{width:33.33333333333333%}.col-sm-5{width:41.66666666666667%}.col-sm-6{width:50%}.col-sm-7{width:58.333333333333336%}.col-sm-8{width:66.66666666666666%}.col-sm-9{width:75%}.col-sm-10{width:83.33333333333334%}.col-sm-11{width:91.66666666666666%}.col-sm-12{width:100%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-11{left:91.66666666666666%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-11{margin-left:91.66666666666666%}}@media(min-width:992px){.container{max-width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-1{width:8.333333333333332%}.col-md-2{width:16.666666666666664%}.col-md-3{width:25%}.col-md-4{width:33.33333333333333%}.col-md-5{width:41.66666666666667%}.col-md-6{width:50%}.col-md-7{width:58.333333333333336%}.col-md-8{width:66.66666666666666%}.col-md-9{width:75%}.col-md-10{width:83.33333333333334%}.col-md-11{width:91.66666666666666%}.col-md-12{width:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.333333333333332%}.col-md-push-2{left:16.666666666666664%}.col-md-push-3{left:25%}.col-md-push-4{left:33.33333333333333%}.col-md-push-5{left:41.66666666666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.333333333333336%}.col-md-push-8{left:66.66666666666666%}.col-md-push-9{left:75%}.col-md-push-10{left:83.33333333333334%}.col-md-push-11{left:91.66666666666666%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-11{right:91.66666666666666%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-11{margin-left:91.66666666666666%}}@media(min-width:1200px){.container{max-width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-1{width:8.333333333333332%}.col-lg-2{width:16.666666666666664%}.col-lg-3{width:25%}.col-lg-4{width:33.33333333333333%}.col-lg-5{width:41.66666666666667%}.col-lg-6{width:50%}.col-lg-7{width:58.333333333333336%}.col-lg-8{width:66.66666666666666%}.col-lg-9{width:75%}.col-lg-10{width:83.33333333333334%}.col-lg-11{width:91.66666666666666%}.col-lg-12{width:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-11{left:91.66666666666666%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-11{margin-left:91.66666666666666%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table thead>tr>th,.table tbody>tr>th,.table tfoot>tr>th,.table thead>tr>td,.table tbody>tr>td,.table tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table caption+thead tr:first-child th,.table colgroup+thead tr:first-child th,.table thead:first-child tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed thead>tr>th,.table-condensed tbody>tr>th,.table-condensed tfoot>tr>th,.table-condensed thead>tr>td,.table-condensed tbody>tr>td,.table-condensed tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8;border-color:#d6e9c6}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td{background-color:#d0e9c6;border-color:#c9e2b3}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede;border-color:#eed3d7}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td{background-color:#ebcccc;border-color:#e6c1c7}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3;border-color:#fbeed5}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td{background-color:#faf2cc;border-color:#f8e5be}@media(max-width:768px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0;background-color:#fff}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>thead>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>thead>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{padding-top:7px;margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-print:before{content:"\e045"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-briefcase:before{content:"\1f4bc"}.glyphicon-calendar:before{content:"\1f4c5"}.glyphicon-pushpin:before{content:"\1f4cc"}.glyphicon-paperclip:before{content:"\1f4ce"}.glyphicon-camera:before{content:"\1f4f7"}.glyphicon-lock:before{content:"\1f512"}.glyphicon-bell:before{content:"\1f514"}.glyphicon-bookmark:before{content:"\1f516"}.glyphicon-fire:before{content:"\1f525"}.glyphicon-wrench:before{content:"\1f527"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent;content:""}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#fff;text-decoration:none;background-color:#428bca}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}}.nav-tabs.nav-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs.nav-justified>.active>a{border-bottom-color:#fff}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:5px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-bottom:1px solid #ddd}.nav-tabs-justified>.active>a{border-bottom-color:#fff}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tabbable:before,.tabbable:after{display:table;content:" "}.tabbable:after{clear:both}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;z-index:1000;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;border-width:0 0 1px}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;z-index:1030}.navbar-fixed-bottom{bottom:0;margin-bottom:0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e6e6e6}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%}a.thumbnail:hover,a.thumbnail:focus{border-color:#428bca}.thumbnail>img{margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table{margin-bottom:0}.panel>.panel-body+.table{border-top:1px solid #ddd}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#fbeed5}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#fbeed5}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#fbeed5}.panel-danger{border-color:#eed3d7}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#eed3d7}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#eed3d7}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}body.modal-open,.modal-open .navbar-fixed-top,.modal-open .navbar-fixed-bottom{margin-right:15px}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{right:auto;left:50%;width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;left:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.affix{position:fixed}@-ms-viewport{width:device-width}@media screen and (max-width:400px){@-ms-viewport{width:320px}}.hidden{display:none!important;visibility:hidden!important}.visible-xs{display:none!important}tr.visible-xs{display:none!important}th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm{display:none!important}tr.visible-sm{display:none!important}th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md{display:none!important}tr.visible-md{display:none!important}th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg{display:none!important}tr.visible-lg{display:none!important}th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs{display:none!important}tr.hidden-xs{display:none!important}th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm{display:none!important}tr.hidden-xs.hidden-sm{display:none!important}th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md{display:none!important}tr.hidden-xs.hidden-md{display:none!important}th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg{display:none!important}tr.hidden-xs.hidden-lg{display:none!important}th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs{display:none!important}tr.hidden-sm.hidden-xs{display:none!important}th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}tr.hidden-sm{display:none!important}th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md{display:none!important}tr.hidden-sm.hidden-md{display:none!important}th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg{display:none!important}tr.hidden-sm.hidden-lg{display:none!important}th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs{display:none!important}tr.hidden-md.hidden-xs{display:none!important}th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm{display:none!important}tr.hidden-md.hidden-sm{display:none!important}th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}tr.hidden-md{display:none!important}th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg{display:none!important}tr.hidden-md.hidden-lg{display:none!important}th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs{display:none!important}tr.hidden-lg.hidden-xs{display:none!important}th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm{display:none!important}tr.hidden-lg.hidden-sm{display:none!important}th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md{display:none!important}tr.hidden-lg.hidden-md{display:none!important}th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg{display:none!important}tr.hidden-lg{display:none!important}th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print{display:none!important}tr.visible-print{display:none!important}th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print{display:none!important}tr.hidden-print{display:none!important}th.hidden-print,td.hidden-print{display:none!important}}incubator-htrace-3.1.0/htrace-hbase/src/test/000077500000000000000000000000001245601110500210345ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/test/java/000077500000000000000000000000001245601110500217555ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/000077500000000000000000000000001245601110500225445ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/apache/000077500000000000000000000000001245601110500237655ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/apache/htrace/000077500000000000000000000000001245601110500252335ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/apache/htrace/impl/000077500000000000000000000000001245601110500261745ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/apache/htrace/impl/HBaseTestUtil.java000066400000000000000000000057771245601110500315370ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.util.Bytes; import org.apache.htrace.HBaseHTraceConfiguration; import org.apache.htrace.SpanReceiver; import org.apache.htrace.SpanReceiverBuilder; import org.junit.Assert; public class HBaseTestUtil { public static Configuration configure(Configuration conf) { Configuration hconf = HBaseConfiguration.create(conf); hconf.set(HBaseHTraceConfiguration.KEY_PREFIX + HBaseSpanReceiver.COLLECTOR_QUORUM_KEY, conf.get(HConstants.ZOOKEEPER_QUORUM)); hconf.setInt(HBaseHTraceConfiguration.KEY_PREFIX + HBaseSpanReceiver.ZOOKEEPER_CLIENT_PORT_KEY, conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, 2181)); hconf.set(HBaseHTraceConfiguration.KEY_PREFIX + HBaseSpanReceiver.ZOOKEEPER_ZNODE_PARENT_KEY, conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT)); return hconf; } public static Table createTable(HBaseTestingUtility util) { Table htable = null; try { htable = util.createTable(Bytes.toBytes(HBaseSpanReceiver.DEFAULT_TABLE), new byte[][]{Bytes.toBytes(HBaseSpanReceiver.DEFAULT_COLUMNFAMILY), Bytes.toBytes(HBaseSpanReceiver.DEFAULT_INDEXFAMILY)}); } catch (IOException e) { Assert.fail("failed to create htrace table. " + e.getMessage()); } return htable; } public static SpanReceiver startReceiver(Configuration conf) { return new SpanReceiverBuilder(new HBaseHTraceConfiguration(conf)).build(); } public static SpanReceiver startReceiver(HBaseTestingUtility util) { return startReceiver(configure(util.getConfiguration())); } public static void stopReceiver(SpanReceiver receiver) { if (receiver != null) { try { receiver.close(); receiver = null; } catch (IOException e) { Assert.fail("failed to close span receiver. " + e.getMessage()); } } } }incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/apache/htrace/impl/TestHBaseSpanReceiver.java000066400000000000000000000165641245601110500332040ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import org.apache.htrace.TimelineAnnotation; import org.apache.htrace.TraceCreator; import org.apache.htrace.TraceTree.SpansByParent; import org.apache.htrace.TraceTree; import org.apache.htrace.protobuf.generated.SpanProtos; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import com.google.common.collect.Multimap; public class TestHBaseSpanReceiver { private static final Log LOG = LogFactory.getLog(TestHBaseSpanReceiver.class); private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); @BeforeClass public static void setUpBeforeClass() throws Exception { UTIL.startMiniCluster(1); } @AfterClass public static void tearDownAfterClass() throws Exception { UTIL.shutdownMiniCluster(); } // Reenable after fix circular dependency @Ignore @Test public void testHBaseSpanReceiver() { Table htable = HBaseTestUtil.createTable(UTIL); SpanReceiver receiver = HBaseTestUtil.startReceiver(UTIL); TraceCreator tc = new TraceCreator(receiver); tc.createThreadedTrace(); tc.createSimpleTrace(); tc.createSampleRpcTrace(); HBaseTestUtil.stopReceiver(receiver); Scan scan = new Scan(); scan.addFamily(Bytes.toBytes(HBaseSpanReceiver.DEFAULT_COLUMNFAMILY)); scan.setMaxVersions(1); ArrayList spans = new ArrayList(); try { ResultScanner scanner = htable.getScanner(scan); Result result = null; while ((result = scanner.next()) != null) { for (Cell cell : result.listCells()) { InputStream in = new ByteArrayInputStream(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); spans.add(new TestSpan(SpanProtos.Span.parseFrom(in))); } } } catch (IOException e) { Assert.fail("failed to get spans from HBase. " + e.getMessage()); } TraceTree traceTree = new TraceTree(spans); Collection roots = traceTree.getSpansByParent().find(Span.ROOT_SPAN_ID); Assert.assertTrue("Trace tree must have roots", !roots.isEmpty()); Assert.assertEquals(3, roots.size()); Map descs = new HashMap(); for (Span root : roots) { descs.put(root.getDescription(), root); } Assert.assertTrue(descs.keySet().contains(TraceCreator.RPC_TRACE_ROOT)); Assert.assertTrue(descs.keySet().contains(TraceCreator.SIMPLE_TRACE_ROOT)); Assert.assertTrue(descs.keySet().contains(TraceCreator.THREADED_TRACE_ROOT)); SpansByParent spansByParentId = traceTree.getSpansByParent(); Span rpcRoot = descs.get(TraceCreator.RPC_TRACE_ROOT); Assert.assertEquals(1, spansByParentId.find(rpcRoot.getSpanId()).size()); Span rpcChild1 = spansByParentId.find(rpcRoot.getSpanId()).iterator().next(); Assert.assertEquals(1, spansByParentId.find(rpcChild1.getSpanId()).size()); Span rpcChild2 = spansByParentId.find(rpcChild1.getSpanId()).iterator().next(); Assert.assertEquals(1, spansByParentId.find(rpcChild2.getSpanId()).size()); Span rpcChild3 = spansByParentId.find(rpcChild2.getSpanId()).iterator().next(); Assert.assertEquals(0, spansByParentId.find(rpcChild3.getSpanId()).size()); Scan iscan = new Scan(); iscan.addColumn(Bytes.toBytes(HBaseSpanReceiver.DEFAULT_INDEXFAMILY), HBaseSpanReceiver.INDEX_SPAN_QUAL); try { ResultScanner scanner = htable.getScanner(iscan); Result result = null; while ((result = scanner.next()) != null) { for (Cell cell : result.listCells()) { InputStream in = new ByteArrayInputStream(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); Assert.assertEquals(SpanProtos.Span.parseFrom(in).getParentId(), Span.ROOT_SPAN_ID); } } } catch (IOException e) { Assert.fail("failed to get spans from index family. " + e.getMessage()); } } private class TestSpan implements Span { SpanProtos.Span span; public TestSpan(SpanProtos.Span span) { this.span = span; } @Override public long getTraceId() { return span.getTraceId(); } @Override public long getParentId() { return span.getParentId(); } @Override public long getStartTimeMillis() { return span.getStart(); } @Override public long getStopTimeMillis() { return span.getStop(); } @Override public long getSpanId() { return span.getSpanId(); } @Override public String getProcessId() { return span.getProcessId(); } @Override public String getDescription() { return span.getDescription(); } @Override public String toString() { return String.format("Span{Id:0x%16x,parentId:0x%16x,pid:%s,desc:%s}", getSpanId(), getParentId(), getProcessId(), getDescription()); } @Override public Map getKVAnnotations() { return Collections.emptyMap(); } @Override public List getTimelineAnnotations() { return Collections.emptyList(); } @Override public void addKVAnnotation(byte[] key, byte[] value) {} @Override public void addTimelineAnnotation(String msg) {} @Override public synchronized void stop() {} @Override public synchronized boolean isRunning() { return false; } @Override public synchronized long getAccumulatedMillis() { return span.getStop() - span.getStart(); } @Override public Span child(String description) { return null; } @Override public String toJson() { return null; } } } incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/apache/htrace/viewer/000077500000000000000000000000001245601110500265345ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-hbase/src/test/java/org/apache/htrace/viewer/TestHBaseSpanViewer.java000066400000000000000000000067561245601110500332430ustar00rootroot00000000000000/* * 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 org.apache.htrace.viewer; import java.io.IOException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.htrace.protobuf.generated.SpanProtos.Span; import org.apache.htrace.protobuf.generated.SpanProtos.TimelineAnnotation; import org.apache.htrace.viewer.HBaseSpanViewer; import org.junit.Test; import org.junit.Assert; public class TestHBaseSpanViewer { private static final Log LOG = LogFactory.getLog(TestHBaseSpanViewer.class); @Test public void testProtoToJson() { Span.Builder sbuilder = Span.newBuilder(); TimelineAnnotation.Builder tlbuilder = TimelineAnnotation.newBuilder(); sbuilder.clear().setTraceId(1) .setParentId(2) .setStart(3) .setStop(4) .setSpanId(5) .setProcessId("pid") .setDescription("description"); for (int i = 0; i < 3; i++) { sbuilder.addTimeline(tlbuilder.clear() .setTime(i) .setMessage("message" + i) .build()); } Span span = sbuilder.build(); try { String json = HBaseSpanViewer.toJsonString(span); String expected = "{\"trace_id\":\"1\"," + "\"parent_id\":\"2\"," + "\"start\":\"3\"," + "\"stop\":\"4\"," + "\"span_id\":\"5\"," + "\"process_id\":\"pid\"," + "\"description\":\"description\"," + "\"timeline\":[" + "{\"time\":\"0\",\"message\":\"message0\"}," + "{\"time\":\"1\",\"message\":\"message1\"}," + "{\"time\":\"2\",\"message\":\"message2\"}]}"; Assert.assertEquals(json, expected); } catch (IOException e) { Assert.fail("failed to get json from span. " + e.getMessage()); } } @Test public void testProtoWithoutTimelineToJson() { Span.Builder sbuilder = Span.newBuilder(); sbuilder.clear().setTraceId(1) .setParentId(2) .setStart(3) .setStop(4) .setSpanId(5) .setProcessId("pid") .setDescription("description"); Span span = sbuilder.build(); try { String json = HBaseSpanViewer.toJsonString(span); String expected = "{\"trace_id\":\"1\"," + "\"parent_id\":\"2\"," + "\"start\":\"3\"," + "\"stop\":\"4\"," + "\"span_id\":\"5\"," + "\"process_id\":\"pid\"," + "\"description\":\"description\"}"; Assert.assertEquals(json, expected); } catch (IOException e) { Assert.fail("failed to get json from span. " + e.getMessage()); } } } incubator-htrace-3.1.0/htrace-hbase/timelines.png000066400000000000000000002033171245601110500217730ustar00rootroot00000000000000PNG  IHDR1j&iCCPICC Profilehy4Um31<nng H`p077ekv9+9;3#ۡX#4p$sG =] +>G=眰ԂDŻK΃ */Bnqᠠ(b~_:p@Op?pS^y.Aн;^^'fB@ D Cn{VHp?SSf7fG-5v,n t˓g T> ?G+ @ pAW/$,P@3p؃е 躣@,Hi \WA( 3tW `Ly؅`c`0y*Lf \a>`X$, ˆ`FX 6 [#x8煋p# 3s2=Sx |>_o"A@ Z38B#&D7b1XF Hj$;RGZ#=as"d) 9F!Pd(fJeCPi|T5GmhZ4ZGϢϣowY&aaT0f7)L 3ƒbٰX]6Vc[߰$E3O3$$IHHIvq8> +^&p뤤 ~ H{HIwTxA Wddddddr $&&%7 $'/&J|B$E E>ce Ep## MJjJ J3 Ք T*^**OrTj.j-jd/h"рO&'hhilhiiZhhhGhбiyeҽMDNEE_G?LA!3όHFAF (ƛ/LJLLYLƘ̖̂g˙7YXYXBY`YfeUggʺFͦv;; { {!{3>G$G)G?.'5ggg.<7N5n6nX1y_n߼|x bj&?n e}BB~B7 ˄GE""EjDEiEEDq9];->.A%a($$KRPCXTTOi!i/eeLde:eedeke\ˍ(4+(*R|$Ţ|[yVSMTeJ]UZڌ:z7  {+ڵzY:T::E:>5kz2zgQFG X < v፬fÍL&&M&LyLM3f̛-_-%,c-\Nh=1noiiCads淭m픝]{F{?CæUy'4g>hޓ'OPe82:83btcE8;Wzv\g>--/G.zv;w+++++,ݽ[\[YtoZ:ںA]<2zXq'볞žyT}ûF&fϋ[hZr[q)m1m>./^|im=*={{_˿~F>2oe 4 * 6S~^}ǐЫ 84:§O?N'L&>>O2O}R7%;2=7c53>1417k7ow$/.~w>'}kvk?:ΰ^!ѹi9;kajG~oQ{}àPp\}½U =ԃPNAWv<  A`qU*f4t! |Xpq~s*=!V+~ i.U =!*"MaH Z֥I[צ?acDc,fojm~eջl)x,} O>pym9OߘiW _BPuPrhmXx\aDHQ,Qg^Ԝ~8^.+x#sJj[ڃ̬s}/8X\T$'t U|DNJܵOE;nl*i\RY}Hŗʅ5$hs֊)o|gxo=j:><07*8:1Oc)i>OM^eyƴ ry6bNl|׈o `{1q+43k~2]g[ѵY[{i{sg콀}CCSfH-+: sc!ħ}"SR}"ޡe` aǼ*^ϱ%s+?E‡Rb%ydldj?*•-UbUzW4ZrN[QRo$jlnnZ`dn{:ܦжn(duU'mMYnB@(1t/l:3TRi(ڨ3e1gΚ `Ȟԝ\F=5roj61{ 7rNZ\Dzi1+)W= ;Ut8 "%[Me%ɷ}VHW2TowՔ˸^T@!#3O[vB㹦f-mRB\/躨^R"&^%S ҿc|2s{g#'1q Ϭ _ӈ?33s_{P=srЏ+*k?~~mج}jfGퟍ݁vxB]1oHq٤d]"e Q& U͇"G +a?),xF(U8[hXxDdTt)Y?9'yUEQ%eR-Y~Fr󚧴uuDtiu4Gx)g,,XޟHI`ci,<}ٕumԽݣƳ+;'7==#4tSԫ3_b݈?'P&)T\fI' ; s,r̕ZX3A(l6[vp8N gs9 p{? x>^owG!{߀ *3!PB"?!b< ]D;1XE!H"2hE BEf "ˑ>rBP(1* @Š2Q*3T7j AA-?]nzAc1e)]iżCKǡ 56"DĒć$$wuʼnp0\:&7%&$$u '"-#m"}OG2xS> ߇ѓIy%=!'[$G+[g&o#'ߢЧ𤈧(xF1DJ %tD-B;aFECKMYG9DMJM@GH5CvΠ~D=I$!݉ >MM-V֗N΃.n^ޓ[8C C)(#Q1qɂ)i2c7,HEȊ+X&XXYϱ>f]`cadKgkf[ebefoc_pcSӃ-K+k[;{ǜ'gWוŧW7oο- .+pK ``P'a*a#T6) JQfQ[K}b1MsbbVJK8IJ KRJJfKHZv7d$eddVdEde. - ߓ @᧢dOڔ:oTU,UUTYUU+T"՚ԁzFWMaxikijehkKuttjfJG7] C+F2Fg:I͍ ԛjf1y՘+' Z8YܱX챢rmrBD74.w7lTm2m>ز c{hjvg$:3;;7Ğ=YqrEWWYt׏nn1n},!D&O2O7z//gGo'G>X>O|I}}(:x>J~ * :v n W<47t%46"<4]TD~)Sm\˧-O7DFF-G~~LΙ11}gϖR.ƽ:'k߄DėIIɢwSxRRSKҹӫ2D2g*fvfede8s{ /! wb%kyby//;_޼sjg3_-*RD^tؤxz qa#KKo"JL~V={'Bb2nD5cug={]kuu6u<4~c_}F|c]Ez2GZ"[~gvvtQ%52嫺n垬^ޞ>ooi;Mp x7>qc0||Dkdn4#W|ưcU'? ~;˃)_ӗgggO=ZMB"bwK7U'[a]i]u^_S:6l767lIn oWIe}g@(_#E#1G\g1|@PZo 1 @a@!fľu!M X#go?Ѕ`ia0NLbLwE Eb` tWaaأv1Vaap Ng;fT6[^`x< σ_߁>ȿL`A#$*}%8*W{Db1X)<Ƀ@" Hv6Y|@#'ߑ(4D:Jwvj5)h C'.0+7aGlvńa1W1FLfbJXS6-a;#t*ܦ$$Q$Inԓ&B#q8\$.W{yCJ %U!"'MjuH'I7dxn2>zOFC&JGBMv39\\܉4Ej.I cFSQBu H&]/]J:J)Js@L;_(d¨rQZFSsSkRQSߤn%2b8FCDLLsfIUhsh~MDJNFWM7@A@JAy\ed0`e(dhcH(Ƙq $Ȕi,| E%eUՙ5sqY5-[7rpssrtq9EƥUۅ=G'gW7wϙoo_/`()#L e &6)eu- &,*V/#*,#A.a%qM$dc)u i:+222=Y{22rz+R()))M* (G*wثQ:Ʃ֬UV/S_PьТ:uOkWPNΨ.nn^>NQ-_چFJF9Fc&"&&æqxb͹̣ZpYD[[rYⵊUD‰QkQT66mlm.ݰ۲7r98: ]w6l}v9pdVciKbxd=!$[8B a<(FT!B9{؇2FRm"i|OQwP8J" JEQQ7X4Z :Jsſw1 /F ca.c1Q eJcس{.g& 9d$$$H*I:HIpN熋qIPZԑ4 C~ȻIxm;d7c2:2Y2kk}1{_ayȇ)26Q)) !PG&QrSPFQRACeIHUGZ:NqDUb8IC1IiE+DI{vΘ.n^>!o2/LvW13Bd:`Vdd~ȼR2Ċgf;;5[[ ;'5{:{#2+9GG=7NNcs9ghbs}=Cs/W7T%S qǯ_?*P-Q/&!X)8.D!%%T#E(/+PHHȊ(h 111O"Aqx]) : STBEpRR1R ep2Z2q2d~ @,G/wB\QU~WAAuE P:%Q Ze1P*2*Q**{jɪjjjWսkjii$4Ӽ9ũUݣCu 6]gЯ_7P4H2xmHe`XfH .cMo&&gL:M֦%fRfqfkJi,-}-[ZY[͞;qDdnu{666Rvvv8{;;*:f;N8@Ι9ҹ+lw!4\=]<)ܽܟ{Py{tx2xyzqz-=u }}|k0~_(l61CBzCEB/n9uoExuJ ##GOkbJڈva71&q7\22| mJyd4IL2Odʺ-| 9gryr_L$~i:e˻W^g)-4ZS,[~7J*nyrN,wx{Ε Jʞ仪wW?vo~VJZ]=} {\zէ2O4`Jlf7yre5uͪ]ja_Pjg ^,tYuB x5ҭ}'gש775y{~_Aw^x};14 u| go1'Oh-'8'&~}1?;KTƴt LҬ9蹱y_W8%}^P_(Y_t\lN=Rz?J~^1[X[\\]3_+_/_ Gܠ8qwccSu3}spn֝~G~{g[i;vNΓ?K`wnn`/fz>f_zu?{~} |`yuPtr0ypprthwqxppR5^:/</C >l4뿎ׂ G/?±iTXtXML:com.adobe.xmp 753 282 X(@IDATx xu/x/¢lK'44ӤW΋ԗn^2m'6MIiHߛj[mIyyJ +-KDxgfw z";{o={̌T$m$fn KRkL)XR8Ό 9k/vvj@Nw>gz'ϖ-% u8ZEV­RkBHyb B .ⷴ@r-IPY'}ً]B ba( 0sPI>RZbCQCNQsI>]]4h'NT-k1~F)3SC=zf2t{CxtibDi@T|vfkD@^W/Zjli JG<9=ƟiPbgoL{% ĝ!7UMNu)lOshY͙}h6>;D$ >u]cspɄ$5Hfk j&DV3E,%vKtB}!֣PiCU=`mSc}rk,+1T,DPoY]jowD:2 7^ǥo HW2A+*W p)"p̩sieAOJGMp0(1|Mia8: 7Op)$<fB݉`7Iݽ#DMHx\(؇IV9MD|pɸ64G11*#x(K^vr {ý{ȪjLpD,pRe+ hq(j?isbbg.n $Rmalb#Nr]AF:I@ii/C|`)9#`4x؂A^՞z>" {Re7cv4?̔i*irW*<䅙#Jɚft9z[铀6Mÿ8TnX3g\_gdo鉤`HJ|ζHtb- sF]K NI8ݓY끅Aj>5Y$U-;K&;![>=}tT!~n7Aђ/Ɩںnn߿ӻsޡўzp*E<׷8lY񬩙d뭝{H$+ѧW6,.ݵ4bG1rtŮ$,P3`J R Op|@zR޾a1ikfgO}}`%g iLGP|fltffz=Ty']yBǓoPoi Rv6`qzh{#{5:?CMoћE:ᨷKc8i__'`y^jc'{ތ={Yq$7 Wg jC!ɍҽ*DF7jOއ&Y2P!u0_W}]wÒ7p]PԸg@뜚8;N50!,\-eO' Se*q$|#uuigѻkPv֎=~h U5ֳ,-W{ҙ#.QӇM'Dvs$>ѷὓͷqb˓V)(#gjmǘJ VtHo:p䣊]wӮbۺEKj uJ*$ò1)EYL--_>؏lVe΄865i̫]s;voaw(&g1Rr<*H7js09y{|^ 5REyOWGFB ZHZ$+،!ѩ|_e^f^@!q2<3o.!љ=> s0fj,k0A͊W[ѽ=]BĬΙKC$Z0W=;of`,k45Ȳg&IRAaϨZ t57 MW;5U C;Ybdgoԝȧ+S(t/Z e* 8V:kA7V2buKKcF<#oQ}U0*0hX0#D"Qz|[xbG?VЬH "&8%b N5OcF( ܐA6;COF"9yCp`X"9qx,(AI˵l+%cB0@aBU"SL%1Ŋ$q8Li||2Kc0)0z~"C;XcUc!ǣ8)3q 3=x8b2<ƺ^οw2Ey DaJ֪(~@MUx@ eqU]ex/:If_l|*NJ͍2 MA|lG\H f4^dg[̢U-gf S"z-ڼ0 ;^OYh|y7d OLQ4CV0ъ5 j%d8aC>Z?4aow R+1H1 vGl(i! nc}wX>= Q9<ҫߏۥ [zĈ&6 /ֶ0F]*V5*/@C.s 䠥C~JQ-8Cd|d&([nWy(ytkuW!n3 aC%+gX+Kg4wW&ԼkgىdChoK#~ul0U]>5gEc@-#P]KrNv2ZN_顝+3-U Yg[KUtȸ<`}FVYj3kj\Bb`g0@oo =Me K˧;27V2]0V҈3%@m#|I@/:!@m'^|mWE֫fw ,Dƒcn<}ެ@uq&X3=3u@̞Ӛih@@ \cOrQ@TM--XФiqTT@@ B@=Dd.:,B4@ ¦%Z{ S/ F@4 ` x%+O@@ pi" b/*z% Vq&g*6-8ZΒtlNX,7ӈcE;O>Ï*Z'oz" }V,h_,9yd貴Z>ЭbJ법+ꛚͪ@ Qgl '* 7K!nlnx{qiqڶ6,,Uf (K>PC{:G6VH.% .(yodϏ޲k݊5bGwمeWHNYZW\кڼwfeAeb+t̛YcuzsަJ6@Ȑ& )/LCb^JN,S,uN:e?EAG2| IEiΙT*KrCZY#S)'liķ6L%WX*Vn}S|r+@4 Ӫ{f>?^VLs{ڛmB=I85ԣg!SMN7gkO{#R8M{he%6[hK@Kxֹ%?oV)~Heٿ{t{5tit'=<v_'+ǿ4 5M'c= z7f7Ωx|b|'`1ؚ{rAM;&u_59Zc|`~=%'݇=*YXEW/ר&ICC  )f^=ԩt#@<3d=8JQѵ IHtC(- }G#C]ܺSce@m6 G=)Ã}$c8M&xהF }[Óa_/sp?'ô?1?wma4#~" b[cj`0۩ ]|4?Z i7}>M}đ4x<ɟ("+ýWJ #x&A1 IEc$gęoXML\S7u$D F!gDll&.raq6 Fila+ &u8NEVU4Bz!78vᶔbbskw|[wSG;;kȠf#1H4PbmDR$z؍.Iد{a|F;e. O+H\TTR9z.wKjJqn2K颷N4\EU̥SYw̧ﶡLmJҲpTXZN}uHҲ""ʹ~$䋅l*]c;ߢ^mR1ɹd=R) S{^*R:|ƥSSj[8~b xs^]R^A0_C"\j)\b^I)EΐQ"''Eh+ƬUkYV LBB^ ˾Kk:(noۖ8!)Wʤ3NH1euOy]Ղ$iP(:ۙw&\ VARb =&Aee5NNTJ$EG'_&ܼ'\Jb+|YIٝIJKnJn&u@r P,rB!E0pxR:q.S=ިUՒ6DUPtp GI\kEz:$e@OzPrX`cwjl |p OOoCĹ(y艗(L<$M9@ĸVb E2P6Ac{S!FqǒVZTk{D'"Ăyt⌐epz)jd[r(-CaqVOEzW pY P{6 naǐql6h1Nc#k2[ X)DV:ȦlOΕ/ٌdU-kpƁtzbͤX pAp`lOӁO}v;w0E xhMI?U-xv(i_ u,i"f R :k:^yN2?eXa L'O3D8}\TtH?ϾFn^TKs͂*)fTie/L]B_FFk:\$YR’]#=VuJJq&IW8=nUI-㲛7$|}l(d\cwR. *^.q$pmiw8B('p1CJ\z]Xvai)RE8f\pXQ8\f`A Yۧq L sKqKSSXVIbU ur&hQocKR:Ìd@0h́,Bc9[tN\(R0yީ(%*ӨHM&6)) L*ɒ)!aHPNy{Ce"LƅDlFIz Dy։,Gͩs,!rhiIɼ IcX®]-HK40:*'5Iel ,Cݒ8]s6ȏaSL~GyVae9r]^7V/m\Vլ+}~Hkegx錚hT.ؠ3{yF븏i o/8yOW~ZW=>z~o{㒖3ݝ6a#/#6J[_~=*BX>k_se-/9O^X+j81"~?ə`3D-9" ڟҒM޿bS?~'à]O>vвc靻Ȗ^|cg"OmM5_U@v6e]ޏT ;VgHyN('ě L(BtGBA]?/X7i JaӬ"#U.2&=\/$1[M6u=>_}e\u;֫7lJfzv tF'+jnD*~?{֔e7}]gn/ٷwn"{e%r`xh]_.XGm^G3"k7~W]uȦ?u?M\q '3߯p_Mury(_Gvz9s0W?رr χ'/ ǃ/p;?߹o?~e j5ǰ)X`ёeLbBŢXHH:=7 aYmIc3MEZ-M&?W-򻵰'_ƚ1Eo'1o>҈gqє| FҳG6mwܧ~3\"l7`y^5=vWɿ_oyOB-ף: |_.7~js]G^#g˪|3~R X3&w` o]7}OyczD ,o>1MD01=?zb}@?ɝ}-O=^>µɗc/޴%8$_1y\xM :0GrO~ΓNZGKD{ a.~2eq.nznY֛*'s2[l=MKL~i7|9Ÿ/K9{UWd9/=OD&O͛xU_ٚ/~Sk\PG.YF2Nzf_[oq77m[;~ܴVaysױ?Y\Ay߽7/y9[T#( M_8n_R#s[/=zf8(?½c ?:O!8kR=e>6)Z*UᎫ|yg[QalQQ'lVW*r.UVۗjGE+|+>G[5_ztű蕈t6 A8-Be1Dĉ1x/~冿ގìj%pC| )m]ėq%Z+ڋ0v=y2ϿL2| D>HN\U2M[R5[Ҹ0Wd&61E+yu o~aԘe%Y!XTbgg@_ 2`ӧc;'l|W^չ on!ƨ}|bɻsV?bɆK~cq!{ecs _0*vtY15N6 k9F%^Li_)}} 4y݅5U`3ƅ1-d--F^3ZZ;;}jP>;O}}(ED I pV`H߳ص8 $\dWVMNx*<Υ _ZGѐ-`##!f&QL-$wlKn>.aNZX0vc-`aM姿\{}9'uݗ?Le+.!<؈;irel"~.!+^b}d5$ڮ9T&67jVUb>d]fr Y%OTxkkSS,X{C.t_ϭ<=4LoN &˻mk ,hg3.Khh#{i>XAQ5lvI80nо߬vqLj gh 9=!͐n4Nٯ/GAT@U,6glQyJ*tbB@͸% ̽ Wb^Mإ. $ ޢ w;;XM줰j:}USf8ű@VI14C!(#ET%G >Rr6 {nEl$ru di;-dS}|:lfuN(`dj>_ %hL69;čAb̜Bj9]V^w)<_bR:+X*F(1E|Se p[atfy)p]N|l=ƒFH! Eu]"$ N8T )pT(<6ФG`G8W(QDm9nX-;vۮ #dp0i"c*DkFd<9`0.vg (b$/K.TVٍl*u4񭡛8c=(H6,>yd0( -iX賓et xlm bp1u/Ȫ\yQ9"qݔV@8`Ɛ*^}5@\2E`N6bhRﬗ:13B+mL}tNSTuuDQ.e G]*OM@ȦlOΕ/Q׿P+aqtzq]&TB%L"`ÑDF\x8ٻC_Z.HdN+fE$NQP N4m`H*[bK{"`xUqq'x|>R! whtʨ Fp",e-cE+֍ k|bITɮhC>!8xVz7+tH jiivzB1E-i9}a9F`XM 84N ߿6|לH5M>n27\8X",bPrhvAai)x^q*7c6T6kAœ0 p>'C6G[P.gVTsDa,55/d+d oUWK̇c@ Qa.O#_S )]j9uOiN^Xb9Ve%=Թ]JgYvRA4dd+Ső@5 )UCޔZ&BL ҈q&]|p#eR)'ub_Sʫ*58\)80ii| 0Sh0{&QX#XbVugR!4Nmt9:T 5"q3|Lg%w"|q\@)Bc${0)Pd0KK#HyDe.!A$L2}SMläz keC銴 ͺ1(Y֘9yD3љ#ʇI!=l&#񻈛hhPcQ ҩ D Phʮ@V%ey)FC+$qɲf5W#PQm[gZ*sFh%dZH~+?UqR*+w~)~4]u> i4,L+b,œS=_S >%N}un0RLR8=ӧ y0E{.E65ces`^><0*.D:#_I3;6g$NV*7әC`hR Ҙ1jPSN`hYEqVni\Ƽ4^@b[bu0),2+y*i.B=nt6NGFZGAɥ`wk/X8RYwV>v WktgBN؞[t]v`)aow_N9R|5UU>D/zѤrV -glX(y^5W\,-gs.0%EkX pY#p^cOW`i_=> }燮_۞;^;+xGn}჻_g`\{?՛>_UX…4\^NnG#QDJ\t `Lmǜ梏vD" $hHEEm0h:8Gοj{>м\}}KuG<۾>yonk*-~傀M.~)'G}9WYj$}첬'I taqb9^eG\sܓ x뼅dlû_wГEGZٟ]cݨ8qseI3eձɗc/޴% C/>իd|n|qə-ؿ؆=YɐG6mwܧ~3\6nxxs9^5=vFŸ/ |}_.7~js]G^,<[_nzË'|[@|8@~JާHS#BmX%y{|˩ @EǞ Ǒ#FߺmO,_څlA}Xʱ;"s5-X.}1Kkm/|& y{%l'%W&Ps|ݴE_ z.n-G=[]dzӶ%sױO-/ŹџtΏ~%s? €Wӕ@I w6;N3*;~ꘌ5nGuտѶwz۳ e;"=m?MӋ$8C_@t@@ 8wgk\oynOke&~q'COsZ?'w {Ӟ'd{єeɌ8>W׼ui:xMdRSH.(rmhc[:𺊰01,eAm7. AX<-;Nqstryu'kSm6ľ`W 9@5/s .{x ?z8s^:]T081~Âi8y{Ӟ.ji_ /@-^f6mްY+l-OV8Zۮ[ȟ]d ,eE#~u=ON}18nu1CYNlkV}};[} BA챽b fWǥ6쀇&Ίe @ `{8zbH+D@@ py p6 \0hwqt&stΎHp?|Ȧ>~^|k5Jց!2 )gq;is;kŝ|3WfL'w}y\BAFD%턿NS.4 _ ofEY~갗0h)ݲj_T_?i/xos4&@<`~FrlZN| z%pj7\}z9Q\^-]ES~|po\86؆Cz"|d#x1ZÉxμ"Ba>{;L}`qU}&7ǎo R3d RlA#'yuKY/pݗ7c?©"w&.͝t#OCLԘm27mR+ /~n>7Ocv܈0 ^şEG_|{;~׿G7N<Cd8+yS Z^[-dPqk0HNVC2DFC:@`#p~1gsǓtdցiɼ;u(!}|敓էte]!^w*¶x O6ްY+l[miI&oji7=׾VeqzMۗxrGI p)"JL ^QYJIdO K?VW*]y PڋW1d1pעlFF s"/`N[RPk.RuId@Oc\[$YgU[sӎ張Ī1hoAWUM*dPRIW $ު (5ؘ-˸cc6spN ZZgw6hV J3Z˜KB#F<Z)IʥRji}^Ϧ=Y-@IDAT3Yqlu>4|(?P c\-IRJXe`5nj< FC^t1`ܘ76ZH-Ezyl/R!V!!MOjbm˪ BɰbFw Yr. RJ[J%U#;!Mء=aD#Qr=#dή< ɷF}(ٜN2 j+Z DA`k/eJOVP@8J%qYN+EP2î~vg(4TI_ÖYl 6_SHEdJ-CǞ.VG_:bnr*~<2p>|*KD/> }uvU-$;|8B.}yPl_q2WtAqOD" ,(xǡ wC3`W`m4/3`@^݁{F}:BqKi5R*\@9!=$'XRr}ᐳxaۥ=C07#n8r5vJ սc)dnf'gt*pq!|c (-apcs. _1uM,29ljD92F|Z8a#"=lPs pK25`˺]tty@$@-"`肚i<<||SKE|81^Η.fP#T=\ 2𷻜#{PPw?"\ƪ\GOJ8_(ⓓ axk[c-xbKGJ4ۤ=ιBR'Y.]́AB ;4@$ +EVrp[ L@QI!ytMO SENPEFœ<+),`N\#ꅁ% GE"T[3``!$.:2|Ȍۉ<%RRlEyQr+aE?*RKvh Y  |\16b O+kNePN+1Lzif& 䓉]ȱm젽HT4: Թ|Q5JV5JRڏ:d'>ۦ&qfp03)5NID2T*MV̊ftNقkWR9̚3\ c(|^,g, spFL/p(Tgo|ğ؋j6sbJO՘^D_?cEhcSF逕sV[,ab\#TYzbUM]Q85iӰ h}7bM ՗. -XrCA;DlpǗP&ZBl+sjw:}֋ E^Ewaمnj T!XᒥT6K͋J,8㲹%L ˣ-0r A3[ax31G\^c L,YbʔUP X p]VSXVɾxhWv*<|\+32ݬiR:/sŢU)fА9EW;r+!N5X$mVbaŔR|U9nHpEQb#$H[uk8nCvkG"D,MdCn0Lu$XK|$_^JaBX$LOsoTZadGiRmP7NOt4tnə}o6 D\K[0(Ы FaUL$Lƭz̿zKD ~=31|ΰ޽5iXɾuO5Pa Ē29jIS2( af0nJ*m(Ÿ- nH(șѷ^NHE\קabQTDJ, tȏBRTd ^qOg*Wm6<-~y!zkbk:|陯(UaiZWdc!t{#`օm+`j/jɹ5\81j2`hnY*)@B"0;~EufLg*/*Ua6SAT8+FUWe/Jku3Τ%)tXf|nYQ^ PI DPc?K?ٍ&$\~WfQ@@ ٷk vξ:C}!K"W xe~W_] !03)ECrH^A@4wQ@"&nEI^X@@ Xf#BZ7r)}/%(eZO_p #4}@il\jbjr5c$-J2;665/4X p)#0>zo3YXo%8 UVOM'=PlV&gWGJ767fe.gqϪ ǂV,$746Z.ƓMC%B^OR{y Pc+QĦ'howV2dž)-DXvh*)VZ]$@#I>&&Ҵzӊ+UY~fj%UYAfOD-3[84gUT0u0>+"/ j.FXZnZoV)72#->5ʲTV'b+2@p]=-gBbCg_ϬYZTzҳBz`(\zH?ؘo*9{BCrk.֑,wdnjKRoJmjv{=E{GO\jF18qQױ+{S8$9~Z sq'Ntͽ?ljNũ=jry!I7ňN3thNlqVq X[WʧTơE&,xC$'yq`&$SDɈmӜT_}9 LPL4$ζ{Cer3;;1\b\%I ҡ`6wLV1Rrb`}Rp'@YcXXE׈{ۧ1DZ6&95@/8^X`&BS4Jb1>bm Orzy>ܮPo":x$c!} Onh>0ؓq}njju9hu>940_ׁXAېBf4V5{uξQaў'/5mb{# ʂa8H[ɇʮv icsb4p`xr2̶e'wlHx2 g#L 2O~m]%w3*$&{؈޸0NM2_$~Ӊ3K i+]&q.8'jnޓ_ew|$%۷Y r>I}*?p MirhIΌLOcKm]pUJ۹wh.*\;.1dcƳf-2vm2 kDZ1zP?D뜧[{ȋ{ҟ0 c3?R0^ ;k sleO| l0?M__'yIBlˆB`By %R}FEM{{_E̛(d~(>)8`!T9{[T$T_wކ&{+=}c*'Fg_JwucZ{m<6Bj&IMN|[o&0B66"*ڢ\3?hh#IyJzI]Lp 鍨oYHכ]I8I{5i,!:@4%j766UUO*ՇfCS!~]ywahodKwA-@P:&~;Sj,L4㥽E=5.KI] o"qxtujuggݷoj#E 6ԗŀYnŤhN|94->hP[ 8y랖:PjrӮj|»\7v+Y#ko=?" FW(+ƦD_-W6zqiO"y(>~׾2@d",aG3Ѣ~٧iV|į@If~Y^s;voťX>Vi D^7jًw 5kMemգ5} nKIp$@vGMw"vѷ}-]&-ΌKґ8:go.44JGMv 5.L.v J6݃1=Mȓeަ3P$d )93A)CMQ 'r`3D*b2Gxmw`̩I%dF!j>7ȁΦmwCTO3g [J^Xb{a@+մ"Ւ:3qgUfJҾ龐tfb6k3@g?L!+ FOӤ3KP sxX$k7a bҥ]U2<ЯAWb@4o" 2s OWx$J#8anA6& %b hCII F+C <?%`%Z 8g>:H26x8NJ5 c  j vGk&7sZFamr#$ 1s@#XFljHBYT[1O$Ɖ '#I#OF#lYYKY`P|s;yKp HbNS#V!0ge/.Z54`^uDqv3_ɇ@ޑh7GfQ܈D4BtY61T+זFh}l%6d,xdɺk>T;Y08/% ^V$P ]2Iן` iJ LI0a6"8vo LmŤSpFA40n7U& d`xg?iB&^NM{D\%R"2lHKP W,%6IO0n5'J\K[?1f ;:QX:Hf;geR ~4ɂu>X"Qx|c kuO@)CuĜu0Ua,;܊wJbUhg#g<S m0)xE- 5k'8o.@Rr!?N W,! uˍ^܍7ozknkH^ܚX 2̗LG%0a5j+k>*Bv)27uU藍ىxC3=`m?c]zHʙQ FCF gq+[՗άI+ Sy P4_IMgdTį@`-"v6Z?ֹ^I| 2i tB}Oe%4+Z7V[;lq}w 7O'GH7hr_"欒lmV?X ={bÕZD~BtR+o`+,?3|ܘvl`VMf4Szlqh T&~je^s-(6fgOV'KYA%Xx@X/(zZ80hGF@ V[{-"59$a5>сqgeڕGXF"g*>Lw fh=<',׌[+\+0g PT@Xv5Ǝ50b`rWcV,_wip)pxG /cJ&YX#7Z%9"Mم+&2Z4U6 JuaN;d PxHyu Νj$:@&". .ZDNfeһ`nQi*9m./FR)!j͂1/l[M `$BtHb:\ e9UjՈ_-n0+dV{:lQ6\f^Rʰ>E4[=ejUɂ5zYT<kf㸝p(6*DF) Ӷ/7OR(O;uQpi߂r88Oɼ  _]GU,ݗAcjU&+J(VA%gqk᪘(t,@qKK;f +MH&9T%EIҐ7xI^E)]VOEYhAᨰ,-y co, <cQ;Wat[*iwYamƊ/csKfOn0,I4(Y )V4iuӤniO-Y^BʴH(JDէBc$}Adz?r\zs MZ_@`߽`VJ+Pf 4se'0bxx,yY$[(YX[ /4u0dǗL-|%|Àinч,;JKP ̸UktH$@`? ! 4KgnT=ݳ= pVbrbtP 'KVaɇN/:WkeҺ3b'qWLbXbȟJ(0O3A=7r ,>o]$fƒ+&T+,ְBz Nb]4FhU6f[ )4bS@?g X혃}Ai~ۛVN d Z0i">H@1)s͡HjT.YHM (76( O@>F0 _O2cgj-9P[c\puzCKM͜Sՠ(=X`3V*N.>Bj.iIHns10邡8=^L,Mb͜4r/0c?p(o%}zL3 -4:$L;ń9dwd sfO Z9%萜lgHW0@g300 䙖`T"nF|"[ݍk۪rCL,@>ΧԲwva v*|8pʕ(@OՉq=s+񥅣q5f2: PJED|hNרRZ`e1NmqHɃ-^K&$rqy@Y_`;]ÇKm~1'"XhӁ ̻hXԽbFSj4Ksc;kwLܪ&0#OCP#HeqjoT2%t ne1w͞\ȹy4u.X_$@Ѽ~g]Zl7gpؽpƈ-7: >iT*"vwy:Y0Is`+^ѕXIy<˃hlV)1\Xn7Q 1dahz5&,pugbo訩oe RNb`O㮘: /jN2D\o gvJC0RH @,A$HpT-Xƭ4f c4C3Ff$ qGxĂU<6cd!4 6~&6dU$".8 n82F8<ˣ۸Oai0lI(P E5B/:RLF~g4`7ԋ82Vji1Wyh͘J@GVNIVTJ:0wԝ IIaOq+Ӎ+v'dgD24ff5M{A$5#\vv{MWV hZvP7I pC-qܱ+U<>{y|iUʿ1*kk}'/b$Ð50>ÙD[YOMҠi&M6ǿh ~z+7-e2;Io7ۋ`'nmmN i1f;4gs]ڭ8K'oV!Lr$Q~- SPhtcŹH _G $uH*C"EUd 4C|Z+ 2Xdj!cz)&"5T(SKOἕR? TjɵVd~}5ev V:si33ۙC5DxdfN~zK-KHL#Se20 FqXg3aN&ɬB[D,R\V`N4LqŘ,4JFWM;SEިbGN̜ 4nT-į@!pCfAv~{:L}P+qܝ[ ()e1%^fY(TJ6Ys{=RUXz?'MJ4lA)v|g/OR(O;u_DK~C֞ x7l7qoClmIԐ)TmTy>(J+^ַlSBS^GR4(Ԟ6]j9WԪGŦ}pkLdZҞQZ҉+s{Eؓ$*ұP^Q֐?B*)MKܛY$XƠRvH܅!c4dlYb~KJ"Pm4X]*pZl7,N&aQu (L#A, jh }cp@BV6u.pj2j4E-i6ū:2 Y %AU(88> h$}&0Ak/aK ɕ 7\sVNG\-SD-ݟxՄz{W'f?$,ƝɉBL%Bv_BHΰڬa ,Ԯq48CӫL͠ &# oO(MMGќދ^E)M=th栿E'Ih4G6\h& 8H>B!O)M1= wAb$]9/Ӡχ2 54gcsBr1.\g9Mx)㖶sm7f->*;T)2(9=,%U#_g!)`!1m)qglAsͬS(Vn-դke_|7m4TgZL'ۦ#jHݍ \{7UmGÀ|>a)SkɁ ӬcZjj4x2|_5h\fkS'Nd!WD#A+08aUˤػVgW pPxw?棍ɾV.1nZ>-@ m>g.DR`ʢ}5]wQoCѹUP |IErZ8ڞOޅ%bPGpc_d} 2Ur# N}ӳȠd\ 1fm* BHAa~9KB~B !5:∕2[XVTN:yIX&k%Dl܍;E^ pMnuH&:3B`)U ib݆u ,, - )|if! 3\{{Ockd6 :LJ,If,MrNB$ΜAålӆe.B@1椎hB ]D9E~`G:3dV&o&"H0)Eâe0`du{pIDa`&<\eһBK5h܊fyI)ƣp-j&2\{ڍO5X,ُ4QuU᳧(*BEmby NA1WfT\49t:\R pi(#Z[Gm]oVl)N%-jk^(1 #i22ۚ[mUYeWxp([2xTd*VT.WC gf5% rq#M ԠIPUIn6rFQbZr N^zNĈ$BI$Q.i BꫪlU޽8 ϧ5v< *dxG PZ'4[rh>V f}^E#zaD %pI p}?rw>PEF5T"I&l TRI^V͹Spd,`2tͩhszCCȧƇ gPMOqf亚KC$0}7D,Oc!!~ 񭮯 ߊt܍^,؋f/^!@`#3$~} )D"s˃xĘ{  K Y>#tuVB@4 YW p#&@@ ?8ߧWGH)nw1†Ҙ[@NK3`cK$ N^g~oy|~^A`x_W4m_uGtm:^1'ٓۓ ׍렉AOv~|_TJUkz6*[^ ,* ĽJIOC{2^Cd\MӵK!_Ur65@v;t\ AJv" v]<Ϙ4pT&f<>*]^;Z7TvǨ/u^P 6waKO=}b:85qoAf!/M^Oa~`Mq*F2]iBk6n̮ǍϷ$sas 6F,<8;.͎r6[9qN,V!Lr$Q~- SPht |/58IՈȨ2&( N=ԴV%rPٽ@!Z| Ӵ/-7\ARU.YjүLqĐ8Fćj9ZF ~)!*DžɱU21Ӿf'V#/[Ze*]œ6.cxz(|"$SJhDԑm&{4:habgGʌZ& 8r2AdS/q34fN$kiZMǻ}FQņ)fc53۩jQbe`SE69ڢl^ j!G+hc,2k>3:h4a&4D;FѼ뼧AUJ֧v)g*ժBJ%]OciT{lP<-Uf J60$S[h-T;3hJm>ys%E &u@MDZZ¥MKaGQI[=pLnf(@ʙoXM\Ѽ ֠ƨ7M[(,)ac(mRM:'ё!\P>hØ ht2-R]HO(Y&8P.OOEY$W)CbUN"K؎JewSV78mwO&UqfthK6"s=`׃u9hAMOr Hh7ʦn)`aRJ`BJI FYd9P(Mm#S0|k](8@O $E$uAt8 w f&=PD#xnVA%^3M+*]h,\ ӣUc5LfΠ4ESDx*nrV(sTm> IN(a O&/l4]<7*Wl46G`߽`TJ+TNJV9޲΀K1vIDiT缬fxŭjsze,-a:9JGCdl~>WL+|T_bX2Z@}(6E 0Fi2N0S| E~}inxUٸkiTjZk@mr`e:VfN]SՠR|sfVUVO\8}^]`$FP2R{X,c UY$ .@IDATF*LҊJ( P4GcBC͡/\NiA;)3| Zejf2t> TYQypgI>&"srz^ 'Ho1`6p3`܅! 1 E/ey7(:%Tfp(:,r4xXVн%['DjNچ&$z4|{Q2θ4Mv`3plCYl. oVWxz9",[PUpt, @7 qܧAܒrSI0Z(T'ǭ7(V?,m8 f?fu"lh>Fhzt4L` oP'ikҀsQiqG$E)&9 &YKK(t.5*xCfh}&ӚjIc^NJ<#>p>b\ c*NW6r#+Oe~8RlhX:{n9n^zew <b9)y ;u4ٝwM VgQl#&X7a;@vAivN8B4^El!n٫r i\ < ;]%'zo~Zp<[@@4oPİ=A> B>D?:"^݇N,iw>4m،NK3`cK\vi f;7ߴU L v"K.W w#;::jB [.\C{*& h}WRu y\}8}O3v2, $V2r WXK 9UA>.NN45w>j-yZe@,SZ_洗DQ2ꩣ`\͊N)QGP>Qsq)we`[9Wj 2֩ DRu3 'ɵVUɦ%%?z,܆+ EŎvaIkڏpܲvIтM:I/z @*Pڕ3bѼ ֠ƨy ,Thkp eQ$hO\; r]`q>[miDjg&y*ÍTEp(=004x^EDbk@.RǑtnuw\d vM|m=bCFi7p@BV6uN{ RC6RL 5"-́B9njU=Fh]GB|+W#E$uAt8 w f&/A8dG5 ӶYMx@as6DGЍ3tݢ睍{\#~O0_*%˕%C+oYg ^/ ̥;^$"^m4Ks^V3 <@k5F|֖‹0L%#Sˡh26?+&%Àa>CkqL*/Auq==PmDF p@8O/.]T黴5(8uQs<,Neo'"[[[[mcɕ4Tb%Yiʑ;]3gYcF$5#:Y6ȭF4 j<C2)ewOH ;ؚA|$Lyqy'0S¥7ˡ ]2,W.#A`x̥\vFx&{GCȋ-#dԼ.R2 )Z[)de!9qvg-į@ |7l 5klZk@mr`e:VfN]SՠR|sfVUVO\8}zuLhFP2Xơ-%g3v_~n>`?xLI$ (#1c;=1Ry蛤x}'7b?Esfy}25x:Rxsì<3n@9`R9=/y_gj0pgdApLCѹ,OEN]V)}5H"v&X![+2(J ҧ³3_Z8 @W [84>bk+Qϥb$11ԑZא} 7baSE%o$rqPέ,=b. s"ד~Ѽ>el¼ oL~/x}lcY~"=Xͭ}:M[h!ZXu9A@@ӻ+bwC;ls;6]G\"0>vwb>Ȭ1rMae%wN[:"r>{y!% Z X\9DBy}˕N*裒Ff` wH2u&_/AA" 5h bC1k<^f`=DXh!ݦa#Vu]WX^a< ,M,/3Q_(Yb!7P9" .c.5aItmUAI\HYjfqA(ʉY8n7y(R54 _s<+1sPm-  njeQe2iL–dLljPUժe !M I()0hb#;>θPv`iQcEB97tIxc1T^3ߴPc٬Rb1} 6lE m/oi4[rthރ{Yf:,Yh H*ZnAKCpnw  9 &6K`|P:[Af7d&Ɍ7qmb<ɓp'N j;%Γg`ZHѨՕlRDVmzBxo(yzxWѡ^Nr *_t3eOe {Pxܠћ d*Mű VS!ڀs`!. d<98(컽l%}kܩ&hqfY)@ٝAI '5z+6J^9,b3FH!o utt X~ʼn@`ge<ڑ¡r6sgލ@ GO[긗N+4IةTWh>&b6a vQȎ1qzq.Rwt^ 7@k݋wyؗ'A9V Q p=f2,Z׳x`$V p4j Luه_I OG.C o ]^ VRjFg߈.njOsS_^18u@ 6iI5z}:t#X +D@\!`\ f\6*@#pPOsÁ@@ pMw4Ҙen$h|+m ׇ0LFGr' o?z[=Se\ڃ m >4/RwtӾNmGKѸMN6JΌ~K L~ν1U"'\oM8ҠNf0J$7z*Kف k" F[ˣ~s?ey݄~x~>( \X3KɸHoXFWӡxCgn5I|Q t8Yn߰o"]L<(B41.-֝j"jS~wQY[t^P ;EƏ ]`/LжI6/zba9Yu~tصX!q6F7Oq7f[I.-/S/E`44\k!ʉ̲}m5 $G/r 0F ̬1[jDdKNI5*3LMkU"Entn0K=elO ʕȨj֚~}5e` u#1">$V2r WXK 9UA>n VAo;tX̘UVM#e*]bOPC{XSɜ8fBb+QGQP>蠍sN V [rctj9Qr(\1:99VӴJWfLmLz.vɑ3= x<^?O- U%9"x;0\$xbmey [A`9>RZ zV`+Cmh^f:ͅJJ֧fG{JNRa晥 JUV\50,mӭM4[P %.ܗ')B\F֞N=رG_6pTT6)ZP4iOj)U*WP7q(($Q2GZR*4 6SB66`P΢ȟc3RVHu<%S-ؔi{B cu4R{*@T\Zwf(ܑ!Ip4\cwЧM%Kɬ84!6z5 S+8eWIfJG]zdl:O :PM]4^ni 6ZW,o`Dq,2DčH\A(@@ > *=Tm@-.IDjP|pioE!;@Yj!nxx.L j&nx4(˧".` ktl(щL kR'qn--M>?uzҊ\DrU `$ae4nav Cw&`%_\}.TȊM@.dЉ4p"# 'R\Y {oYg@ ̥;^$"^m4Ks^V3 <@k5F|֖‹L%#Sˡh26?+&0V0`6zdqbL*/Auq=ؼDnea-&u;@q:"yYԤOD+`,JL#< !n^9bKsz,6}htdf gg;Mdk 2g`5.RvGİ#;IT*F%Ï/Yvss fV2xFGO`fK}ot`Fx{94KbdL?3Xd \Ulb~ tvdh " ]rgk/{a|▬JFt/"M'\ > j 5klZ󑩵@mr`V:VfN!Sՠo.3،꩓ Oګ˖yh$hp.o{XLa6d6:>-`weOh05Ay IⓄyihN G*Ύ[wrb6s :1u*S3 OSj;@Z&fudoh.3c15꩹S,|CIbR9=>y_gj0s۠,OPL3Q"~d7$rnlnmUu4*3h|rлv74[i\1~A=s+񥅣q[NX:!V"tKiHb;#ǵ!i<NM*z!3$H?ʵ[ .fŌ}.cF]y1u"bg1#FfV1 hnoir& W|cu90 A#]#1Lߧ߀!u y#m~1d4MJQm`7|0R}ԠȬ1rޮ;-]QHN@h X},}npog9Y[YE?@RAaSrR@`YڋU׿mo mC44 QuUIIx}0=6,S^(YbsI4׆Z-2.1ڏ)gԑ1hVT Y̅uЯf $fzݬOC h 1:6BupbWx e4d=қfJBJrHz%UUک\U!zG؄$z(0hb# x/i`w܄i' 0F%_+P3l P I@oCR$5p z~7x뛇U#hHBqMi# êTu"lI,J< e[f:6' 6Pɸ'6'pn7_P_ 8O;:{~<(NR{V55 o36tVMP&RBUXI6d&J,q1¶OZ<%Γ56BQ+)٤(]逦Utkxz*r?] eԽ7ML ~=,bo&a3mʬQ`v̩G|xiӀjݘp8,ypȧ!Y{L[rڮJhqBT$SH#,u'XIW,ϙ'V|jh q&8g_}Ӱ7Oc9]xwbvwgbg/wvOw$k5~RXsSMH-VgVr.VWĕ) 9m驋hs /is#+Oe"X?|,9#WooŐ5ɽ7 <N gHNcM&O*k~^ǙYkq/uJK'2p4wdG(8 pP}(D@@ phŵV*h|SG+d$56ehfr;2dtr ;]Q#A,hX~3O|qqEv/<^{sb[pwx/nم&߼X\dK{P,DG+>@>gda4tW=UՊt )Ǩ 8*@JG)`C0M{ʗ>_WJz-XL3q>>.>>OmX;\&cnk%Wl-g}jLRʰ+'3Kg1ZUܙjdD JUɳsgASgO,>wL0-9pN ɾ-[R#пx?I|ZܳijWWγQ\8ß8;|xuX_܃CI p3 ֞lcy1^T8)'*vx9`|cs>2 l0)D- c $rƙs+ixU׼:r-Q"WڹC W5v#;ɞz~} ??kH{N|3/|/~8"{<G>ȿc?|P̃u]eg%]Kt΀ϾZ3K>=3:g~,?~n c>|' s$XxJIGӞ>ٹ3_gϒlu Q|>۳P󯦥/^"IfQL G> ̩HrevR 24se ;@:W[9͒ꜗL5ZbQ,"DSIv|r(犉i0_х4h6L*/A18Ukt"#\5" !nHǞ:FO1{2{Сt̬ R<\ԁ3Ϟ{u8-&#s¡ @j|>-V Myej-9P[c\pu,rCKM͜O&OUK0 6czz,i( Z5a.b65$9@jXy}['{b9" Gߍ?~{%9{ev鰳Ǒ&^c~p{{={_]\9|ۣv yc]wqļy }׷E`w#h|gA>ҷy lA8ν>6_O3'C3_Z8 @W [84>E&ƴNרRZ`e1$V;#ǵ!֖s өSE%oihHU"}!|J=?a+^g߁x^~ 2G~6g)^SculKR^yr=+<0Ӯ4_CsOe{sYP؝D K.FS9024yfg톷~ctSʽ?Dˮӌ]O^|׿}dME^ ؗ1»A7 ]!N_EN^J,Jkt+g ZނFg}l?eߜbuJ.P$\3oc\V_k^Y\yhl;SXa7/.O|ɧgrml~? _}^2Z~]zȩFvuvJO}J(m .6_G_{/^~tT/=H'W/cy<y(w< 7 a'ןΤek?_Nf1ޑǗ,RJ;1{T flxZaЊEjn,rrvh j<g!U pOn|ΕW?S=Uʽ?Nma|~*g>~Wy_ZH,ܖ*>{ؓ|_]3O3glMLp |Ƒnk[X ʧ󿙦XfD~r}0or MMJޤmGw9*y28?~!pÿ-8C_?}PO:Nb΅3>G`pip5 0kRCS8iډ2Ew-F>~LPxx.Ҽw:nP0޼DS&C2V%fx|}[*HjG/0);GhUBWJpwwq`ƿ7!rW걻-OsMAOs@hRZ4:}l?k-dԬ49 C@4{ܴ4{_!@ #CSGÕ|sQU,7߬]fa @@ pxh"|.Z/%?u_DQ[7DPѩ@@ pS in(!ؓx|~9 ~a33SڑbV< {rB(@`/! |t5,k VNnd7[[[=ſRZõ(s+\h@@ pH[HWSi@@ p.ScaTWg4Y%W \)]+EL oƓIJ4Cn2Z]_^iil{ >A¼3M˝4"/ ?|S1gŗ/nqn[&:#[7 Z%\f(,v]Ki_GߟYGk e'U\kO9z4Rќ5:Gg4#6QH3FI#3PA+JF''˕Q"X x~]V:'74s\x9:S[\#wAVHm9v-l&0?0?gw#+O|Q9:Sl/|aO!"/պ{jE* E8xښ.$@7/?Nr-K&!%YTyS ^4hļ 98x#4 ÄՐQ[=E>S>=3nt4/Cl5Q%j"0Cr$aZ.a50Xnq.Qc^pHt[;L$SZȡC^nPN C^g?{R fo=_?zp~_~v\/|'_j~N/^4?2u( GiXl.H|$X&a!VӴJu;TLz ^tR%7KּVY5 H\ -N`<߄dns B^ʋ ~źg%5\Jw~n}5Y3C}FɵLpG7J;#__MИ=*Z $^D-ՄDJFѺ&FG𥈛' apjoг@_AѼg,|ԃ6,.$Nw>p-  + Gʮ(ܲIC]5N e˃=nIQQ$4PBpT Q Djp x2 k[[$@ijZ7P3v%1H5)!dQUU 7AnЎ∷'9ivCV6u䐷.fk j4%(uk׭2d?WE$@@ pM䦜y#},gҐ߾@O.<y_sz܆B?O|(!#@xsgNp\Oäx2L`ѲL4,&݄=&=^yyGl+nr(^5/ .mt'uFw-tU~;̖p`{': ! *H.4M&=9sf楴uXs4Cwtel:}͎LB?;S ( $b(Ϧ*qgQ"c4 eZ^1_n`MJ+-OV9>dFEow4g)7@n(_ `טu ,ZR"A+-DY%a&uqAʸ覎͉] ᨰIzYN{^sg~ߛQ\=}}|$\X*)ѯ-, Od :mMr5^/bRɛ&dAg̖%ɨ#-:'x,h׏_" 6![xW?WΟɧG#W̥Ga6H_ONv˄|~1ܢu^_OȟELcɧ/DHv`mU?,'"M$t.&,JҏE.)a&Г~% Զ,ō ;@ Kq5WG|$:DŽ\VLǠt`80\kPA@$cp!AFPW@paLd"j!B/\}*1UTʐkyKynJQtu(dR bľR>4O .AfV@ ާiB^v/[Ixx;3ʇM[;&FL%czu=怐ieEf&fHtcWȑ<1EBTs" 6 \Oߧ@ako<ً7տ7_b3P8+}<<[O]_%BRIt?r#uI?Se")80yylQ2[?C&hfNMVLs͐N-AZ В 0|La(}OrIy:oH*O2j!lFW~-['N03@khLl!?އ w}@q͝Ba=wotO۳c$kRSASn+9I9HN*NȦ4c#ﰐH)F4^SU" wgM߲nT|irs~| _]{Sܼ _Sk_?~% 2a|ww{AG9 d#Ƿ2Or,狨Ob'I6U#114,SUޏhWǾ2pa`Kh$vUEw겓قEl sCLsu9zۆɪeؤ$ K*[ΛP[.ɺ$$AShv˴< RG˰h4:I6ݪ.N* " %J|n"%EkZEf{ @AE63ҹ.>to~o}s᷾͗_js忤,l=>wYWsx+ؓ{pc;۠:_*;7]XJr6s^l2.OgwS4'!;)xd j# =puvyBEˉ:dw߈" 0ϯ N$ tC5q 65s+K?۝~X,f*S_z˰h'% {6lqGzeL욣]=ݵE#9,2w~DVt0ݺB ZW{ tf>rzM.n}v~cAAݍ-azUN:wB3e3c -ӭd|AFRۍzt(݋|ͼz==n۵xb#_Hd60Z9ѻX'4D@N$~h~pQ ׍p6ށBg.ogXy'xV4{sݻ^~zЗ/ۏ ^9OX9ٞci1Wړ q 1Τ^7~ r0OF )B dr }%vi-$J9G?lkk}Xz+;Aa>O%zҟ?+#G#S{y:-*Sq " I!`V>9, "Tv)8"w͟>Or#y.6|dɞGCw%hӼ+v@O %˅hB>ۭ nS?Kyp h@~x@yD@Nf0M ɾkŸ_['_Ѧ9mOSx;*@DrFÎ!!8dHZ)4?E' !',X"  `*)-;0hi5?~ 8qЦ9qHBD@S/,q)%ɕ:^Ù5t0!'Ӝ,X" .{3` "p McjF7F a/7r^DM] s?˃yD@~ {fn0MCUU"`[Li:X쵎tM:t?=l2T2[t>vN{m7up}ͶP+ht},9dFD`pP["MYswp>KQdtЈ "ݰzԙ[=ur(.{'=2S ?tAo%FLY4udGD` 8{vޔ sJflLF4N-%J*ńƩ3ICi0;Swy;urelۡJma QWXαM SN$zCΥDSW()%QT2*i+1#kjU|NbM"81 XKbmdr 5;γ8,d-5R|fϏ[f(YEDSψbPH0- xKT]\Eu>XmEIabq|*q\<#bU3|JV4v? prS>}M,ghqcvs+ 4Vn*:/'ilѦu3l3T^)h^faYD-Nb^|(!n=H49eA7tX..RPhn+y; I"@מ'6 ml(2,o5ޕ$6x6a|"K[ᠽAl*,Yɵ&5騜nGP[rFd < yk` ٱ i\+ĕ50hv%'Q&m*9pW鴛`vkN3K a!Shoڧ+HBD`P0k2 !{<$V̖jp ¿K73僌P%8.si=٬vj8_.HIj,U48? {Ab<^ɰhߺ4:Iٖ٪.N* B9 RD\@(GX^V4\p@D"8,2N`Lb4W"۩ZUt^W\U`S|"J` #W&0@k\|4`zI5*tkWd:C?"tiUa[`h-IyV *jf< [A.(Nmύ/`ICؾB+Ux[`y؜^\li%Fl.6 x:kraqSb8[JXvAӸlޛǼ@Fp_x%0H=K.G <E2" [x@l3~>_홦ux=XEMZ|,`մ2g.Tu5W+DD-8Z}1+h*b#㩯>Y[{$1Gd3ȉ"^ qxw o\c~M9;H2&DB`j=V~ 1Qn۟j<~?!a1""4.ADxpOsx-b 4FDx`N(Q+iNS{@D@i@Dxmb>o@D|SS5M]Ll a gq4Mi<" }!pCwoq#ho^?/~r"%¹?hBy;6oݹ8Yk'?N?4OcaDtHS+Fg,0Qy&Dڕ  8U'[v` @I<lJ`!" oǾ{k:D(o>|qr{υ>F+w >.GΙǞ׾< < {%/Q`Ӥ J*s4ހ3T3qtg" !p Gerξ24O_|vC0B߯Ol!EslKQBaG#;cE`|{^v%.U. )1 ZϜŔ[tCΥDSW(XH J2c2!#J#JFȚZϜK*fDL~=g w+ORҹW_\~˵{h^l@؉l J 0U "D׆8]*VKLMU⬺0OUchT!c>8F[i8l-=xu3'4 XlF]n,Y]U@-z9OV&FPA‘Q2kpX...όFrGdѱP%*I`@۷_{O|w/?Eȗ&Joy<{C¿LǰW4x0o /p4 #cڵ͕ZntrEEڳV$NQ$ش77  &כVXb(%ˍz x"CEu32 pҋn57w'୹ms$e vFx\kn,Bag3 Ԯ dECp|:C%0t%\~*cO9j"6a ? 94V#\ڵ!T|X*)ѯ-, Odx5i₥N[Sk\MW`mi*Ԉ4OG||<˕RCe0CrdA˒dT̑]ϒkzh<d\ @#x?ya &iΟ9/|?y+?LQ#wo}#>WcVat spX>D*LP?oͬg0"bt|Ng1!W/L FyJ "V `| lntK^R;ł'=V+Q4[Ixx3R$*{o:@t7:6!D`hQ@ȴwkl@_ ,,Kb$ KQp$/1&"˽O " ~ߥWn~ eu=F?O}j&a@*' qr~/pZ+a_N y 29U@ Qf9uv0g,Ñ۳c$ .d]I |J~1pU`qOiN36[DN1~{ui" /{/mw$&h"{+HYc&c$]ZW])Jz$&fpUUl~^"YJ] \2>o0 g ZJ1/â+itvlVՖ٪.ς bTcHIZV A " Z_Wx?7Iȕ EUVd'A~(Iɑxi&є R0OH Q榖Kb,,ώKF{Thxυe2,j7,!KqZ|U}dt˟P~+-lZ^aN Klu:O.'*Z17YR`!;5173!j\831xBō&?~Q " *3c'⳿2 {ȝ6'uڵ_s;Zo+_z% %tG~1=lP,dC&%1Ȳ$KL6j}y韡H^6Ǯ]eUD˕x.ǯF`o 'ǖhA*^k^8=Dx#` 8{ cِn;w9wN9KÿK{lP+U %3Ut498&0;GP3GjLzwjz=wF;)!8:_SxN]Xv FQcv30&D@wڏ8=YPiZJ 6طEU"婞Wnom-{x̟ B<|(Lʭ&ۉ]3#! " ÂY ݶ7œ[!S'+=٩!dnS}ҫg!W}*ey§̦a`JN5\X[U|mRbbʉGoȹCMMBr Ad&l*#l7]ɈbWV1 "p p~xs|٣6+8TDX,]uKR'W7P - NLba>^Q[ٔ3b}6.Ϋ\^Ǭܑȫys!ߠ]jȏU8z6}F=Zڳ#;«ys!?Qۚv\]jW_[y_xe¬eo|^Ghrz=}3 5֋yg-((؊Q[]]靖NJMV#_׬XV5,>RkZxhר[{t-G:52_кO«DWZjVo%^M3|Ox={{Gy xrS{TV~k5]s{glP5l4zk<[ypQmsOgxծ1voh0߫8\y?|6-6-6-6-6-6-6-6-o?ypۯ>Nk        _}쏏ϳ?f99v뭬j͑՜i]Yoa֟/F}y#w>BϏ?>)VgjY5R/UfchUmQ.clHUXvܼozخZǫOپ<^z7V/{ȭ뎸jn\Oz7GznW׻XsvW}Z/zXDnV/G>{Pcx(Hwv.)2ꍭջ{}~~zӬXV5,>RkZxXը[{^_^8Z9Ew~kbl.>n$LluGzkGSgzil={{Gy ~15,7ռGkVs5zkj]jk^=N1^:>^Nkk]cmޜa4W nq0>l.[l.[l.[l.[l.[l.[l.[l.[~ഷ_}"-6-6-6-6-6-6-6-6-o~<g!rrl˹^OjNuo녣+Vj=Gi[+=zӣcH>QG=G]cuz>Ǐϳcxʱ^Nk,b7^,~$v槣[svxQoZ#+r%瞞~8Zx"r^ 5Gbjyֽ_IzVcL9Qcm<g:6Ts~U>RQX39F|nSyTKpޮz;׷*j5^QUyz9cyTߋuGy3WͭG\Sؙ[]Uzj̣Q^,X/ޮ;ʛjn=⚪6~:gl.[ZO.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l.[l." ~0dIENDB`incubator-htrace-3.1.0/htrace-zipkin/000077500000000000000000000000001245601110500175105ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/pom.xml000066400000000000000000000073501245601110500210320ustar00rootroot00000000000000 4.0.0 htrace-zipkin jar htrace org.apache.htrace 3.1.0-incubating .. htrace-zipkin http://incubator.apache.org/projects/htrace.html UTF-8 maven-assembly-plugin true org.apache.maven.plugins maven-source-plugin maven-javadoc-plugin maven-compiler-plugin org.apache.maven.plugins maven-gpg-plugin org.apache.rat apache-rat-plugin maven-deploy-plugin maven-assembly-plugin jar-with-dependencies org.apache.htrace htrace-core ${project.version} provided commons-logging commons-logging provided com.google.guava guava provided junit junit test org.apache.thrift libthrift 0.9.0 commons-codec commons-codec 1.7 incubator-htrace-3.1.0/htrace-zipkin/src/000077500000000000000000000000001245601110500202775ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/000077500000000000000000000000001245601110500212235ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/000077500000000000000000000000001245601110500221445ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/com/000077500000000000000000000000001245601110500227225ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/com/twitter/000077500000000000000000000000001245601110500244245ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/com/twitter/zipkin/000077500000000000000000000000001245601110500257305ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/org/000077500000000000000000000000001245601110500227335ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/org/apache/000077500000000000000000000000001245601110500241545ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/org/apache/htrace/000077500000000000000000000000001245601110500254225ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/org/apache/htrace/impl/000077500000000000000000000000001245601110500263635ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/org/apache/htrace/impl/ZipkinSpanReceiver.java000066400000000000000000000302001245601110500327740ustar00rootroot00000000000000/* * 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 org.apache.htrace.impl; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.twitter.zipkin.gen.LogEntry; import com.twitter.zipkin.gen.Scribe; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.htrace.HTraceConfiguration; import org.apache.htrace.Span; import org.apache.htrace.SpanReceiver; import org.apache.htrace.zipkin.HTraceToZipkinConverter; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.protocol.TProtocolFactory; import org.apache.thrift.transport.TFramedTransport; import org.apache.thrift.transport.TIOStreamTransport; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** * Zipkin is an open source tracing library. This span receiver acts as a bridge between HTrace and * Zipkin, that converts HTrace Span objects into Zipkin Span objects. *

* HTrace spans are queued into a blocking queue. From there background worker threads will * batch the spans together and then send them through to a Zipkin collector. */ public class ZipkinSpanReceiver implements SpanReceiver { private static final Log LOG = LogFactory.getLog(ZipkinSpanReceiver.class); /** * Default hostname to fall back on. */ private static final String DEFAULT_COLLECTOR_HOSTNAME = "localhost"; /** * Default collector port. */ private static final int DEFAULT_COLLECTOR_PORT = 9410; // trace collector default port. /** * this is used to tell scribe that the entries are for zipkin.. */ private static final String CATEGORY = "zipkin"; /** * Whether the service which is traced is in client or a server mode. It is used while creating * the Endpoint. */ private static final boolean DEFAULT_IN_CLIENT_MODE = false; /** * How long this receiver will try and wait for all threads to shutdown. */ private static final int SHUTDOWN_TIMEOUT = 30; /** * How many spans this receiver will try and send in one batch. */ private static final int MAX_SPAN_BATCH_SIZE = 100; /** * How many errors in a row before we start dropping traces on the floor. */ private static final int MAX_ERRORS = 10; /** * The queue that will get all HTrace spans that are to be sent. */ private final BlockingQueue queue; /** * Factory used to encode a Zipkin Span to bytes. */ private final TProtocolFactory protocolFactory; /** * Boolean used to signal that the threads should end. */ private final AtomicBoolean running = new AtomicBoolean(true); /** * The thread factory used to create new ExecutorService. *

* This will be the same factory for the lifetime of this object so that * no thread names will ever be duplicated. */ private final ThreadFactory tf; //////////////////// /// Variables that will change on each call to configure() /////////////////// private HTraceToZipkinConverter converter; private ExecutorService service; private HTraceConfiguration conf; private String collectorHostname; private int collectorPort; public ZipkinSpanReceiver(HTraceConfiguration conf) { this.queue = new ArrayBlockingQueue(1000); this.protocolFactory = new TBinaryProtocol.Factory(); tf = new ThreadFactoryBuilder().setDaemon(true) .setNameFormat("zipkinSpanReceiver-%d") .build(); configure(conf); } private void configure(HTraceConfiguration conf) { this.conf = conf; this.collectorHostname = conf.get("zipkin.collector-hostname", DEFAULT_COLLECTOR_HOSTNAME); this.collectorPort = conf.getInt("zipkin.collector-port", DEFAULT_COLLECTOR_PORT); // initialize the endpoint. This endpoint is used while writing the Span. initConverter(); int numThreads = conf.getInt("zipkin.num-threads", 1); // If there are already threads runnnig tear them down. if (this.service != null) { this.service.shutdownNow(); this.service = null; } this.service = Executors.newFixedThreadPool(numThreads, tf); for (int i = 0; i < numThreads; i++) { this.service.submit(new WriteSpanRunnable()); } } /** * Set up the HTrace to Zipkin converter. */ private void initConverter() { InetAddress tracedServiceHostname = null; // Try and get the hostname. If it's not configured try and get the local hostname. try { String host = conf.get("zipkin.traced-service-hostname", InetAddress.getLocalHost().getHostAddress()); tracedServiceHostname = InetAddress.getByName(host); } catch (UnknownHostException e) { LOG.error("Couldn't get the localHost address", e); } short tracedServicePort = (short) conf.getInt("zipkin.traced-service-port", -1); byte[] address = tracedServiceHostname != null ? tracedServiceHostname.getAddress() : DEFAULT_COLLECTOR_HOSTNAME.getBytes(); int ipv4 = ByteBuffer.wrap(address).getInt(); this.converter = new HTraceToZipkinConverter(ipv4, tracedServicePort); } private class WriteSpanRunnable implements Runnable { /** * scribe client to push zipkin spans */ private Scribe.Client scribeClient = null; private final ByteArrayOutputStream baos; private final TProtocol streamProtocol; public WriteSpanRunnable() { baos = new ByteArrayOutputStream(); streamProtocol = protocolFactory.getProtocol(new TIOStreamTransport(baos)); } /** * This runnable converts a HTrace span to a Zipkin span and sends it across the zipkin * collector as a thrift object. The scribe client which is used for rpc writes a list of * LogEntry objects, so the span objects are first transformed into LogEntry objects before * sending to the zipkin-collector. *

* Here is a little ascii art which shows the above transformation: *

     *  +------------+   +------------+   +------------+              +-----------------+
     *  | HTrace Span|-->|Zipkin Span |-->| (LogEntry) | ===========> | Zipkin Collector|
     *  +------------+   +------------+   +------------+ (Scribe rpc) +-----------------+
     *  
*/ @Override public void run() { List dequeuedSpans = new ArrayList(MAX_SPAN_BATCH_SIZE); long errorCount = 0; while (running.get() || queue.size() > 0) { Span firstSpan = null; try { // Block for up to a second. to try and get a span. // We only block for a little bit in order to notice if the running value has changed firstSpan = queue.poll(1, TimeUnit.SECONDS); // If the poll was successful then it's possible that there // will be other spans to get. Try and get them. if (firstSpan != null) { // Add the first one that we got dequeuedSpans.add(firstSpan); // Try and get up to 100 queues queue.drainTo(dequeuedSpans, MAX_SPAN_BATCH_SIZE - 1); } } catch (InterruptedException ie) { // Ignored. } if (dequeuedSpans.isEmpty()) continue; // If this is the first time through or there was an error re-connect if (scribeClient == null) { startClient(); } // Create a new list every time through so that the list doesn't change underneath // thrift as it's sending. List entries = new ArrayList(dequeuedSpans.size()); try { // Convert every de-queued span for (Span htraceSpan : dequeuedSpans) { // convert the HTrace span to Zipkin span com.twitter.zipkin.gen.Span zipkinSpan = converter.convert(htraceSpan); // Clear any old data. baos.reset(); // Write the span to a BAOS zipkinSpan.write(streamProtocol); // Do Base64 encoding and put the string into a log entry. LogEntry logEntry = new LogEntry(CATEGORY, Base64.encodeBase64String(baos.toByteArray())); entries.add(logEntry); } // Send the entries scribeClient.Log(entries); // clear the list for the next time through. dequeuedSpans.clear(); // reset the error counter. errorCount = 0; } catch (Exception e) { LOG.error("Error when writing to the zipkin collector: " + collectorHostname + ":" + collectorPort, e); errorCount += 1; // If there have been ten errors in a row start dropping things. if (errorCount < MAX_ERRORS) { try { queue.addAll(dequeuedSpans); } catch (IllegalStateException ex) { LOG.error("Drop " + dequeuedSpans.size() + " span(s) because queue is full"); } } closeClient(); try { // Since there was an error sleep just a little bit to try and allow the // zipkin collector some time to recover. Thread.sleep(500); } catch (InterruptedException e1) { // Ignored } } } closeClient(); } /** * Close out the connection. */ private void closeClient() { // close out the transport. if (scribeClient != null) { scribeClient.getInputProtocol().getTransport().close(); scribeClient = null; } } /** * Re-connect to Zipkin. */ private void startClient() { if (this.scribeClient == null) { TTransport transport = new TFramedTransport(new TSocket(collectorHostname, collectorPort)); try { transport.open(); } catch (TTransportException e) { e.printStackTrace(); } TProtocol protocol = protocolFactory.getProtocol(transport); this.scribeClient = new Scribe.Client(protocol); } } } /** * Close the receiver. *

* This tries to shut * * @throws IOException */ @Override public void close() throws IOException { running.set(false); service.shutdown(); try { if (!service.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)) { LOG.error("Was not able to process all remaining spans to write upon closing in: " + SHUTDOWN_TIMEOUT + " " + TimeUnit.SECONDS + ". There could be un-sent spans still left." + " They have been dropped."); } } catch (InterruptedException e1) { LOG.warn("Thread interrupted when terminating executor.", e1); } } @Override public void receiveSpan(Span span) { if (running.get()) { try { this.queue.add(span); } catch (IllegalStateException e) { LOG.error("Error trying to append span (" + span.getDescription() + ") to the queue." + " Blocking Queue was full."); } } } } incubator-htrace-3.1.0/htrace-zipkin/src/main/java/org/apache/htrace/zipkin/000077500000000000000000000000001245601110500267265ustar00rootroot00000000000000HTraceToZipkinConverter.java000066400000000000000000000150511245601110500342420ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/java/org/apache/htrace/zipkin/* * 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 org.apache.htrace.zipkin; import com.twitter.zipkin.gen.Annotation; import com.twitter.zipkin.gen.AnnotationType; import com.twitter.zipkin.gen.BinaryAnnotation; import com.twitter.zipkin.gen.Endpoint; import com.twitter.zipkin.gen.Span; import com.twitter.zipkin.gen.zipkinCoreConstants; import org.apache.htrace.TimelineAnnotation; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class is responsible for converting a HTrace.Span to a Zipkin.Span object. To use the Zipkin * infrastructure (collector, front end), we need to store the Span information in a zipkin specific * format. This class transforms a HTrace:Span object to a Zipkin:Span object. *

* This is how both Span objects are related: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
HTrace:SpanZipkin:Span
TraceIdTraceId
ParentIdParentId
SpanIdid
DescriptionName
startTime, stopTimeAnnotations (cs, cr, sr, ss)
Other annotationsAnnotations
*

*/ public class HTraceToZipkinConverter { private final int ipv4Address; private final short port; private static final Map DEFAULT_PORTS = new HashMap(); static { DEFAULT_PORTS.put("hmaster", 60000); DEFAULT_PORTS.put("hregionserver", 60020); DEFAULT_PORTS.put("namenode", 8020); DEFAULT_PORTS.put("datanode", 50010); } public HTraceToZipkinConverter(int ipv4Address, short port) { this.ipv4Address = ipv4Address; this.port = port; } /** * Converts a given HTrace span to a Zipkin Span. *

    *
  • First set the start annotation. [CS, SR], depending whether it is a client service or not. *
  • Set other id's, etc [TraceId's etc] *
  • Create binary annotations based on data from HTrace Span object. *
  • Set the last annotation. [SS, CR] *
*/ public Span convert(org.apache.htrace.Span hTraceSpan) { Span zipkinSpan = new Span(); String serviceName = hTraceSpan.getProcessId().toLowerCase(); Endpoint ep = new Endpoint(ipv4Address, (short) getPort(serviceName), serviceName); List annotationList = createZipkinAnnotations(hTraceSpan, ep); List binaryAnnotationList = createZipkinBinaryAnnotations(hTraceSpan, ep); zipkinSpan.setTrace_id(hTraceSpan.getTraceId()); if (hTraceSpan.getParentId() != org.apache.htrace.Span.ROOT_SPAN_ID) { zipkinSpan.setParent_id(hTraceSpan.getParentId()); } zipkinSpan.setId(hTraceSpan.getSpanId()); zipkinSpan.setName(hTraceSpan.getDescription()); zipkinSpan.setAnnotations(annotationList); zipkinSpan.setBinary_annotations(binaryAnnotationList); return zipkinSpan; } /** * Add annotations from the htrace Span. */ private List createZipkinAnnotations(org.apache.htrace.Span hTraceSpan, Endpoint ep) { List annotationList = new ArrayList(); // add first zipkin annotation. annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_SEND, hTraceSpan.getStartTimeMillis(), ep, true)); annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_RECV, hTraceSpan.getStartTimeMillis(), ep, true)); // add HTrace time annotation for (TimelineAnnotation ta : hTraceSpan.getTimelineAnnotations()) { annotationList.add(createZipkinAnnotation(ta.getMessage(), ta.getTime(), ep, true)); } // add last zipkin annotation annotationList.add(createZipkinAnnotation(zipkinCoreConstants.SERVER_SEND, hTraceSpan.getStopTimeMillis(), ep, false)); annotationList.add(createZipkinAnnotation(zipkinCoreConstants.CLIENT_RECV, hTraceSpan.getStopTimeMillis(), ep, false)); return annotationList; } /** * Creates a list of Annotations that are present in HTrace Span object. * * @return list of Annotations that could be added to Zipkin Span. */ private List createZipkinBinaryAnnotations(org.apache.htrace.Span span, Endpoint ep) { List l = new ArrayList(); for (Map.Entry e : span.getKVAnnotations().entrySet()) { BinaryAnnotation binaryAnn = new BinaryAnnotation(); binaryAnn.setAnnotation_type(AnnotationType.BYTES); binaryAnn.setKey(new String(e.getKey())); binaryAnn.setValue(e.getValue()); binaryAnn.setHost(ep); l.add(binaryAnn); } return l; } /** * Create an annotation with the correct times and endpoint. * * @param value Annotation value * @param time timestamp will be extracted * @param ep the endopint this annotation will be associated with. * @param sendRequest use the first or last timestamp. */ private static Annotation createZipkinAnnotation(String value, long time, Endpoint ep, boolean sendRequest) { Annotation annotation = new Annotation(); annotation.setHost(ep); // Zipkin is in microseconds if (sendRequest) { annotation.setTimestamp(time * 1000); } else { annotation.setTimestamp(time * 1000); } annotation.setDuration(1); annotation.setValue(value); return annotation; } private int getPort(String serviceName) { if (port != -1) { return port; } Integer p = DEFAULT_PORTS.get(serviceName); if (p != null) { return p; } return 80; } } incubator-htrace-3.1.0/htrace-zipkin/src/main/thrift/000077500000000000000000000000001245601110500225235ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/main/thrift/scribe.thrift000066400000000000000000000014211245601110500252120ustar00rootroot00000000000000# Copyright 2012 Twitter Inc. # # 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. namespace java com.twitter.zipkin.gen enum ResultCode { OK, TRY_LATER } struct LogEntry { 1: string category, 2: string message } service Scribe { ResultCode Log(1: list messages); } incubator-htrace-3.1.0/htrace-zipkin/src/main/thrift/zipkinCore.thrift000066400000000000000000000043611245601110500260660ustar00rootroot00000000000000# Copyright 2012 Twitter Inc. # # 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. namespace java com.twitter.zipkin.gen namespace rb Zipkin //************** Collection related structs ************** // these are the annotations we always expect to find in a span const string CLIENT_SEND = "cs" const string CLIENT_RECV = "cr" const string SERVER_SEND = "ss" const string SERVER_RECV = "sr" // this represents a host and port in a network struct Endpoint { 1: i32 ipv4, 2: i16 port // beware that this will give us negative ports. some conversion needed 3: string service_name // which service did this operation happen on? } // some event took place, either one by the framework or by the user struct Annotation { 1: i64 timestamp // microseconds from epoch 2: string value // what happened at the timestamp? 3: optional Endpoint host // host this happened on 4: optional i32 duration // how long did the operation take? microseconds } enum AnnotationType { BOOL, BYTES, I16, I32, I64, DOUBLE, STRING } struct BinaryAnnotation { 1: string key, 2: binary value, 3: AnnotationType annotation_type, 4: optional Endpoint host } struct Span { 1: i64 trace_id // unique trace id, use for all spans in trace 3: string name, // span name, rpc method for example 4: i64 id, // unique span id, only used for this span 5: optional i64 parent_id, // parent span id 6: list annotations, // list of all annotations/events that occured 8: list binary_annotations // any binary annotations 9: optional bool debug = 0 // if true, we DEMAND that this span passes all samplers } incubator-htrace-3.1.0/htrace-zipkin/src/test/000077500000000000000000000000001245601110500212565ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/test/java/000077500000000000000000000000001245601110500221775ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/test/java/org/000077500000000000000000000000001245601110500227665ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/test/java/org/apache/000077500000000000000000000000001245601110500242075ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/test/java/org/apache/htrace/000077500000000000000000000000001245601110500254555ustar00rootroot00000000000000incubator-htrace-3.1.0/htrace-zipkin/src/test/java/org/apache/htrace/TestHTraceSpanToZipkinSpan.java000066400000000000000000000124231245601110500334640ustar00rootroot00000000000000/* * 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 org.apache.htrace; import com.twitter.zipkin.gen.zipkinCoreConstants; import org.apache.htrace.Span; import org.apache.htrace.Trace; import org.apache.htrace.impl.MilliSpan; import org.apache.htrace.impl.POJOSpanReceiver; import org.apache.htrace.zipkin.HTraceToZipkinConverter; import org.junit.Assert; import org.junit.Test; import java.io.IOException; import java.util.Collection; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * Creates HTrace and then convert it to Zipkin trace and checks whether it is a valid span or not. */ public class TestHTraceSpanToZipkinSpan { private static final String ROOT_SPAN_DESC = "ROOT"; @Test public void testHTraceToZipkin() throws IOException { POJOSpanReceiver psr = new POJOSpanReceiver(HTraceConfiguration.EMPTY); Trace.addReceiver(psr); Span rootSpan = new MilliSpan(ROOT_SPAN_DESC, 1, Span.ROOT_SPAN_ID, 100, "test"); Span innerOne = rootSpan.child("Some good work"); Span innerTwo = innerOne.child("Some more good work"); innerTwo.stop(); innerOne.stop(); rootSpan.addKVAnnotation("foo".getBytes(), "bar".getBytes()); rootSpan.addTimelineAnnotation("timeline"); rootSpan.stop(); for (Span s : new Span[] {rootSpan, innerOne, innerTwo}) { com.twitter.zipkin.gen.Span zs = new HTraceToZipkinConverter(12345, (short) 12).convert(s); assertSpansAreEquivalent(s, zs); } } @Test public void testHTraceAnnotationTimestamp() throws IOException, InterruptedException { String traceName = "testHTraceAnnotationTimestamp"; long startTime = System.currentTimeMillis() * 1000; Span ms = new MilliSpan(traceName, 1, Span.ROOT_SPAN_ID, 2, traceName); Thread.sleep(500); long annoStartTime = System.currentTimeMillis() * 1000; Thread.sleep(500); ms.addTimelineAnnotation("anno"); Thread.sleep(500); long annoEndTime = System.currentTimeMillis() * 1000; Thread.sleep(500); ms.stop(); long endTime = System.currentTimeMillis() * 1000; com.twitter.zipkin.gen.Span zs = new HTraceToZipkinConverter(12345, (short) -1).convert(ms); // Check to make sure that all times are in the proper order. for (com.twitter.zipkin.gen.Annotation annotation : zs.getAnnotations()) { // CS and SR should be before the annotation // the annotation should be in between annotationStart and annotationEnd times // SS and CR should be after annotationEnd and before endtime. if (annotation.getValue().equals(zipkinCoreConstants.CLIENT_SEND) || annotation.getValue().equals(zipkinCoreConstants.SERVER_RECV)) { assertTrue(startTime <= annotation.getTimestamp()); assertTrue(annotation.getTimestamp() <= annoStartTime); } else if (annotation.getValue().equals(zipkinCoreConstants.CLIENT_RECV) || annotation.getValue().equals(zipkinCoreConstants.SERVER_SEND)) { assertTrue(annoEndTime <= annotation.getTimestamp()); assertTrue(annotation.getTimestamp() <= endTime); } else { assertTrue(annoStartTime <= annotation.getTimestamp()); assertTrue(annotation.getTimestamp() <= annoEndTime); assertTrue(annotation.getTimestamp() <= endTime); } } } @Test public void testHTraceDefaultPort() throws IOException { MilliSpan ms = new MilliSpan("test", 1, 2, 3, "hmaster"); com.twitter.zipkin.gen.Span zs = new HTraceToZipkinConverter(12345, (short) -1).convert(ms); for (com.twitter.zipkin.gen.Annotation annotation:zs.getAnnotations()) { assertEquals((short)60000, annotation.getHost().getPort()); } ms = new MilliSpan("test", 1, 2, 3, "HregIonServer"); // make sure it's all lower cased zs = new HTraceToZipkinConverter(12345, (short) -1).convert(ms); for (com.twitter.zipkin.gen.Annotation annotation:zs.getAnnotations()) { assertEquals((short)60020, annotation.getHost().getPort()); } } private void assertSpansAreEquivalent(Span s, com.twitter.zipkin.gen.Span zs) { assertEquals(s.getTraceId(), zs.getTrace_id()); if (s.getParentId() != Span.ROOT_SPAN_ID) { assertEquals(s.getParentId(), zs.getParent_id()); } assertEquals(s.getSpanId(), zs.getId()); Assert.assertNotNull(zs.getAnnotations()); if (ROOT_SPAN_DESC.equals(zs.getName())) { assertEquals(5, zs.getAnnotations().size());// two start, two stop + one timeline annotation assertEquals(1, zs.getBinary_annotations().size()); } else { assertEquals(4, zs.getAnnotations().size()); } } } incubator-htrace-3.1.0/pom.xml000066400000000000000000000265421245601110500162660ustar00rootroot00000000000000 4.0.0 org.apache apache 12 org.apache.htrace htrace 3.1.0-incubating pom Apache HTrace A tracing framework for use with distributed systems written in java http://htrace.incubator.apache.org htrace-core htrace-zipkin htrace-hbase htrace-flume The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo A business-friendly OSS license scm:git:http://git-wip-us.apache.org/repos/asf/incubator-htrace.git scm:git:https://git-wip-us.apache.org/repos/asf/incubator-htrace.git https://git-wip-us.apache.org/repos/asf?p=incubator-htrace.git JIRA http://issues.apache.org/jira/browse/HTRACE hudson https://builds.apache.org/view/H-L/view/HTrace/ Developer List dev-subscribe@htrace.incubator.apache.org dev-unsubscribe@htrace.incubator.apache.org dev@htrace.incubator.apache.org http://mail-archives.apache.org/mod_mbox/incubator-htrace-dev/ Commits List commits-subscribe@htrace.incubator.apache.org commits-unsubscribe@htrace.incubator.apache.org http://mail-archives.apache.org/mod_mbox/incubator-htrace-commits/ Issues List issues-subscribe@htrace.incubator.apache.org issues-unsubscribe@htrace.incubator.apache.org http://mail-archives.apache.org/mod_mbox/incubator-htrace-issues/ jon Jonathan Leavitt jonathan.leavitt@cloudera.com -7 Cloudera http://www.cloudera.com eclark Elliott Clark eclark@apache.org -7 Cloudera http://www.cloudera.com org.apache.maven.plugins maven-source-plugin 2.1.2 attach-sources package jar-no-fork maven-javadoc-plugin 2.8.1 attach-javadocs package jar org.apache.maven.plugins maven-jar-plugin 2.4 test-jar org.apache.rat apache-rat-plugin 0.11 package check **/.settings/** **/dependency-reduced-pom.xml **/generated/** */.settings/* */generated/* .git/** **/README.md **/src/go/bin/* **/src/go/pkg/* **/bootstrap-3.3.1/** **/*.min.js **/d3.min.js **/gopkg.in/** **/github.com/** **/golang.org/** **/Godeps/** maven-compiler-plugin 2.5.1 1.6 1.6 true UTF-8 org.apache.maven.plugins maven-gpg-plugin 1.1 sign-artifacts deploy sign maven-deploy-plugin 2.7 deploy deploy deploy org.apache.maven.plugins maven-shade-plugin 2.1 org.apache.maven.plugins maven-gpg-plugin maven-deploy-plugin org.apache.maven.plugins maven-site-plugin 3.4 org.apache.maven.wagon wagon-ssh 2.2 org.apache.maven.doxia doxia-module-markdown 1.6 lt.velykis.maven.skins reflow-velocity-tools 1.1.1 org.apache.velocity velocity 1.7 ${basedir}/src/main/site UTF-8 UTF-8 maven-assembly-plugin 2.5.3 false gnu htrace-${project.version} src/main/assembly/src.xml org.apache.maven.plugins maven-surefire-plugin true 1.6 false commons-logging commons-logging 1.1.1 com.google.guava guava 12.0.1 junit junit 4.10 test htrace.incubator.apache.org HTrace Website at incubator.apache.org file:///tmp incubator-htrace-3.1.0/src/000077500000000000000000000000001245601110500155275ustar00rootroot00000000000000incubator-htrace-3.1.0/src/main/000077500000000000000000000000001245601110500164535ustar00rootroot00000000000000incubator-htrace-3.1.0/src/main/assembly/000077500000000000000000000000001245601110500202725ustar00rootroot00000000000000incubator-htrace-3.1.0/src/main/assembly/src.xml000066400000000000000000000065211245601110500216070ustar00rootroot00000000000000 src tar.gz true target/ test/ .classpath **/*.orig .project .git .gitignore .settings/ **/src/go/bin/** **/pkg/** **/build/** ${project.basedir}/src src 0644 0755 ${project.basedir}/bin bin 0755 0755 ${project.basedir}/src src ${project.basedir}/tools tools ${project.basedir} . pom.xml LICENSE.txt NOTICE.txt CHANGES.txt DISCLAIMER.txt BUILDING.txt README.md 0644 incubator-htrace-3.1.0/src/main/site/000077500000000000000000000000001245601110500174175ustar00rootroot00000000000000incubator-htrace-3.1.0/src/main/site/markdown/000077500000000000000000000000001245601110500212415ustar00rootroot00000000000000incubator-htrace-3.1.0/src/main/site/markdown/index.md000066400000000000000000000250361245601110500227000ustar00rootroot00000000000000 Apache HTrace is an Apache Incubator project. To add HTrace to your project, see detail on how to add it as a dependency. Formerly, HTrace was available at org.htrace. API --- Using HTrace requires adding some instrumentation to your application. Before we get into the details, lets review our terminology. HTrace borrows [Dapper's](http://research.google.com/pubs/pub36356.html) terminology. Span: The basic unit of work. For example, sending an RPC is a new span, as is sending a response to an RPC. Span's are identified by a unique 64-bit ID for the span and another 64-bit ID for the trace the span is a part of. Spans also have other data, such as descriptions, key-value annotations, the ID of the span that caused them, and process ID's (normally IP address). Spans are started and stopped, and they keep track of their timing information. Once you create a span, you must stop it at some point in the future. Trace: A set of spans forming a tree-like structure. For example, if you are running a distributed big-data store, a trace might be formed by a put request. ### How to add tracing to your application To instrument your system you must: 1. Attach additional information to your RPC's. In order to create the causal links necessary for a trace, HTrace needs to know about the causal relationships between spans. The only information you need to add to your RPC's is two 64-bit longs. If tracing is enabled (Trace.isTracing() returns true) when you send an RPC, attach the ID of the current span and the ID of the current trace to the message. On the receiving end of the RPC, check to see if the message has the additional tracing information above. If it does, start a new span with the information given (more on that in a bit). 2. Wrap your thread changes. HTrace stores span information in java's ThreadLocals, which causes the trace to be "lost" on thread changes. The only way to prevent this is to "wrap" your thread changes. For example, if your code looks like this: ````java Thread t1 = new Thread(new MyRunnable()); ... ```` Just change it to look this: ````java Thread t1 = new Thread(Trace.wrap(new MyRunnable())); ```` That's it! `Trace.wrap()` takes a single argument (a runnable or a callable) and if the current thread is a part of a trace, returns a wrapped version of the argument. The wrapped version of a callable and runnable just knows about the span that created it and will start a new span in the new thread that is the child of the span that created the runnable/callable. There may be situations in which a simple `Trace.wrap()` does not suffice. In these cases all you need to do is keep a reference to the "parent span" (the span before the thread change) and once you're in the new thread start a new span that is the "child" of the parent span you stored. For example: Say you have some object representing a "put" operation. When the client does a "put," the put is first added to a list so another thread can batch together the puts. In this situation, you might want to add another field to the Put class that could store the current span at the time the put was created. Then when the put is pulled out of the list to be processed, you can start a new span as the child of the span stored in the Put. 3. Add custom spans and annotations. Once you've augmented your RPC's and wrapped the necessary thread changes, you can add more spans and annotations wherever you want. For example, you might do some expensive computation that you want to see on your traces. In this case, you could start a new span before the computation that you then stop after the computation has finished. It might look like this: ````java Span computationSpan = Trace.startSpan("Expensive computation."); try { //expensive computation here } finally { computationSpan.stop(); } ```` HTrace also supports key-value annotations on a per-trace basis. Example: ````java Trace.currentTrace().addAnnotation("faultyRecordCounter".getBytes(), "1".getBytes()); ```` `Trace.currentTrace()` will not return `null` if the current thread is not tracing, but instead it will return a `NullSpan`, which does nothing on any of its method calls. The takeaway here is you can call methods on the `currentTrace()` without fear of NullPointerExceptions. ###Samplers `Sampler` is an interface that defines one function: ````java boolean next(T info); ```` All of the `Trace.startSpan()` methods can take an optional sampler. A new span is only created if the sampler's next function returns true. If the Sampler returns false, the `NullSpan` is returned from `startSpan()`, so it's safe to call `stop()` or `addAnnotation()` on it. As you may have noticed from the `next()` method signature, Sampler is parameterized. The argument to `next()` is whatever piece of information you might need for sampling. See `Sampler.java` for an example of this. If you do not require any additional information, then just ignore the parameter. HTrace includes a sampler that always returns true, a sampler that always returns false and a sampler returns true some percentage of the time (you pass in the percentage as a decimal at construction). HTrace comes with several standard samplers, including `AlwaysSampler`, `NeverSampler`, `ProbabilitySampler`, and `CountSampler`. An application can use the `SamplerBuilder` to create one of these standard samplers based on the current configuration. ````java HTraceConfiguration hconf = createMyHTraceConfiguration(); Sampler sampler = new SamplerBuilder(hconf).build(); ```` ####Trace.startSpan() There is a single method to create and start spans: `startSpan()`. For the `startSpan()` methods that do not take an explicit Sampler, the default Sampler is used. The default sampler returns true if and only if tracing is already on in the current thread. That means that calling `startSpan()` with no explicit Sampler is a good idea when you have information that you would like to add to a trace if it's already occurring, but is not something you would want to start a whole new trace for. If you are using a sampler that makes use of the `T info` parameter to `next()`, just pass in the object as the last argument. If you leave it out, HTrace will pass `null` for you (so make sure your Samplers can handle `null`). Aside from whether or not you pass in an explicit `Sampler`, there are other options you have when calling `startSpan()`. For the next section I am assuming you are familiar with the options for passing in `Samplers` and `info` parameters, so when I say "no arguments," I mean no additional arguments other than whatever `Sampler`/`info` parameters you deem necessary. You can call `startSpan()` with no additional arguments. In this case, `Trace.java` will start a span if the sampler (explicit or default) returns true. If the current span is not the `NullSpan`, the span returned will be a child of the current span, otherwise it will start a new trace in the current thread (it will be a `ProcessRootMilliSpan`). All of the other `startSpan()` methods take some parameter describing the parent span of the span to be created. The versions that take a `TraceInfo` or a `long traceId` and `long parentId` will mostly be used when continuing a trace over RPC. The receiver of the RPC will check the message for the additional two `longs` and will call `startSpan()` if they are attached. The last `startSpan()` takes a `Span parent`. The result of `parent.child()` will be used for the new span. `Span.child()` simply returns a span that is a child of `this`. ###Span Receivers In order to use the tracing information consisting of spans, you need an implementation of `SpanReceiver` interface which collects spans and typically writes it to files or databases or collector services. The `SpanReceiver` implementation must provide a `receiveSpan` method which is called from `Trace.deliver` method. You do not need to explicitly call `Trace.deliver` because it is internally called by the implementation of `Span`. ````java public interface SpanReceiver extends Closeable { public void receiveSpan(Span span); } ```` HTrace comes with several standard span receivers, such as `LocalFileSpanReceiver`. An application can use the `SpanReceiverBuilder` to create a particular type of standard `SpanReceiver` based on the current configuration. Once a SpanReceiver has been created, it should be registered with the HTrace framework by calling `Trace.addReceiver`. ````java HTraceConfiguration hconf = createMyHTraceConfiguration(); SpanReceiverBuilder builder = new SpanReceiverBuilder(hconf); SpanReceiver spanReceiver = builder.build(); if (spanReceiver != null) { Trace.addReceiver(spanReceiver); } ```` ####Zipkin htrace-zipkin provides the `SpanReceiver` implementation which sends spans to [Zipkin](https://github.com/twitter/zipkin) collector. You can build the uber-jar (htrace-zipkin-*-jar-withdependency.jar) for manual setup as shown below. This uber-jar contains all dependencies except htrace-core and its dependencies. $ cd htrace-zipkin $ mvn compile assembly:single ####HBase Receiver See htrace-hbase for an Span Receiver implementation that writes HBase. Also bundled is a simple Span Viewer. Testing Information ------------------------------- The test that creates a sample trace (TestHTrace) takes a command line argument telling it where to write span information. Run `mvn test -DargLine="-DspanFile=FILE\_PATH"` to write span information to FILE_PATH. If no file is specified, span information will be written to standard out. If span information is written to a file, you can use the included graphDrawer python script in tools/ to create a simple visualization of the trace. Or you could write some javascript to make a better visualization, and send a pull request if you do :). Publishing to Maven Central ------------------------------- See [OSSRH-8896](https://issues.sonatype.org/browse/OSSRH-8896) for repository vitals. incubator-htrace-3.1.0/src/main/site/site.xml000066400000000000000000000054671245601110500211210ustar00rootroot00000000000000 Apache HTrace http://htrace.incubator.apache.org/ bootswatch-flatly top true A tracing framework for use with distributed systems written in java Home lt.velykis.maven.skins reflow-maven-skin 1.1.1 incubator-htrace-3.1.0/tools/000077500000000000000000000000001245601110500161005ustar00rootroot00000000000000incubator-htrace-3.1.0/tools/README.txt000066400000000000000000000004371245601110500176020ustar00rootroot00000000000000graphDrawer.py requires: -graphviz -python-graph (http://code.google.com/p/python-graph/) Just cat any span files created by LocalFileSpanReceiver's into graphDrawer.py and it will create the trace graphs. There must be a graphs directory in the directory from which the script is run. incubator-htrace-3.1.0/tools/graphDrawer.py000077500000000000000000000042731245601110500207310ustar00rootroot00000000000000#!/usr/bin/env python # 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. import sys import gv import json from json import JSONDecoder from datetime import datetime from pygraph.classes.graph import graph from pygraph.classes.digraph import digraph from pygraph.readwrite.dot import write from collections import defaultdict ROOT_SPAN_ID = 0x74ace def buildGraph(nid): for child in spansByParent[nid]: desc = spansBySpanId[child]["Description"] + "(" + str(spansBySpanId[child]["Stop"] - spansBySpanId[child]["Start"]) + ")" #graphviz can't handle '\' desc = desc.replace("\\", "") gr.add_node(child, [("label", desc)]) gr.add_edge((nid, child)) buildGraph(child) def loads_invalid_obj_list(s): decoder = JSONDecoder() objs = [decoder.decode(x) for x in s.split()] return objs nodes = loads_invalid_obj_list(sys.stdin.read().strip()) spansBySpanId = {s["SpanID"]:s for s in nodes} spansByParent = defaultdict(set) for node in spansBySpanId.values(): spansByParent[node["ParentID"]].add(node["SpanID"]) count = 0 for x in spansByParent[ROOT_SPAN_ID]: count += 1 gr = digraph() gr.add_node(x, [("label", spansBySpanId[x]["Description"] + "(" + str(spansBySpanId[x]["Stop"] - spansBySpanId[x]["Start"]) + ")")]) buildGraph(x) dot = write(gr) gvv = gv.readstring(dot) gv.layout(gvv,'dot') gv.render(gvv,'png','./graphs/' + str(datetime.now()) + str(spansBySpanId[x]["Description"])[:10] + '.png') print("Created " + str(count) + " images.")