├── AUTHORS ├── LICENSE ├── README.md ├── backoff.go ├── collect.go ├── doc.go ├── gen-go ├── scribe │ ├── GoUnusedProtection__.go │ ├── scribe-consts.go │ ├── scribe-remote │ │ └── scribe-remote.go │ └── scribe.go └── zipkin │ ├── GoUnusedProtection__.go │ ├── zipkin-consts.go │ └── zipkin.go ├── go.mod ├── go.sum ├── http.go ├── httpctx17.go ├── httpctxgen.go.m4 ├── httpxctx.go ├── rand.go ├── register.go ├── request.go ├── scribe.go ├── scribe.thrift ├── udp.go └── zipkin.thrift /AUTHORS: -------------------------------------------------------------------------------- 1 | Space Monkey, Inc. 2 | Peter Teichman 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # monkit-zipkin 2 | 3 | A plugin for http://github.com/spacemonkeygo/monkit that supports Zipkin. 4 | 5 | See the docs at http://godoc.org/gopkg.in/spacemonkeygo/monkit-zipkin.v2 6 | 7 | ## Example usage 8 | 9 | Your main method gets set up something like this: 10 | 11 | ```go 12 | package main 13 | 14 | import ( 15 | "net/http" 16 | 17 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2" 18 | "gopkg.in/spacemonkeygo/monkit.v2" 19 | "gopkg.in/spacemonkeygo/monkit.v2/environment" 20 | "gopkg.in/spacemonkeygo/monkit.v2/present" 21 | ) 22 | 23 | func main() { 24 | environment.Register(monkit.Default) 25 | go http.ListenAndServe("localhost:9000", present.HTTP(monkit.Default)) 26 | collector, err := zipkin.NewScribeCollector("zipkin.whatever:9042") 27 | if err != nil { 28 | panic(err) 29 | } 30 | zipkin.RegisterZipkin(monkit.Default, collector, zipkin.Options{ 31 | Fraction: 1}) 32 | 33 | ... 34 | } 35 | ``` 36 | 37 | Once you've done that, you need to make sure your HTTP handlers pull Zipkin 38 | `Context` info from the `Request`. That's easy to do with 39 | `zipkin.ContextWrapper`. 40 | 41 | ```go 42 | func HandleRequest(ctx context.Context, w http.ResponseWriter, 43 | r *http.Request) { 44 | defer mon.Task()(&ctx)(nil) 45 | 46 | ... whatever 47 | } 48 | 49 | func DoTheThing(ctx context.Context) (err error) { 50 | defer mon.Task()(&ctx)(&err) 51 | return http.Serve(listener, zipkin.ContextWrapper( 52 | zipkin.TraceHandler(zipkin.ContextHTTPHandlerFunc(HandleRequest)))) 53 | } 54 | ``` 55 | 56 | Last, your outbound HTTP requests need to pass through Context info: 57 | 58 | ```go 59 | func MakeRequest(ctx context.Context) (err error) { 60 | defer mon.Task()(&ctx)(&err) 61 | req, err := http.NewRequest(...) 62 | if err != nil { 63 | return err 64 | } 65 | resp, err := zipkin.TraceRequest(ctx, http.DefaultClient, req) 66 | ... 67 | } 68 | ``` 69 | 70 | ## License 71 | 72 | Copyright (C) 2016 Space Monkey, Inc. 73 | 74 | Licensed under the Apache License, Version 2.0 (the "License"); 75 | you may not use this file except in compliance with the License. 76 | You may obtain a copy of the License at 77 | 78 | http://www.apache.org/licenses/LICENSE-2.0 79 | 80 | Unless required by applicable law or agreed to in writing, software 81 | distributed under the License is distributed on an "AS IS" BASIS, 82 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 83 | See the License for the specific language governing permissions and 84 | limitations under the License. 85 | -------------------------------------------------------------------------------- /backoff.go: -------------------------------------------------------------------------------- 1 | package zipkin 2 | 3 | import "time" 4 | 5 | // backoff implements a backoff policy, randomizing its delays and 6 | // saturating at its last value. 7 | type backoff struct { 8 | millis []int 9 | } 10 | 11 | // defaultBackoff is a backoff policy ranging up to 5s. 12 | var defaultBackoff = backoff{ 13 | []int{0, 10, 10, 100, 100, 500, 500, 3000, 3000, 5000}, 14 | } 15 | 16 | // duration returns the time duration of the n'th wait cycle in its 17 | // backoff policy. This is backoff.millis[n], randomized to avoid 18 | // thundering herds. 19 | func (b backoff) duration(n int) time.Duration { 20 | if n >= len(b.millis) { 21 | n = len(b.millis) - 1 22 | } 23 | 24 | return time.Duration(fudge(b.millis[n])) * time.Millisecond 25 | } 26 | 27 | // fudge returns a random integer uniformly distributed in the range 28 | // [0.5 * millis .. 1.5 * millis] 29 | func fudge(millis int) int { 30 | if millis == 0 { 31 | return 0 32 | } 33 | 34 | return millis/2 + rng.Intn(millis) 35 | } 36 | -------------------------------------------------------------------------------- /collect.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package zipkin 16 | 17 | import ( 18 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2/gen-go/zipkin" 19 | ) 20 | 21 | // TraceCollector is an interface dealing with completed Spans on a 22 | // SpanManager. See RegisterZipkin. 23 | type TraceCollector interface { 24 | // Collect gets called with a Span whenever a Span is completed on a 25 | // SpanManager. 26 | Collect(span *zipkin.Span) 27 | } 28 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /* 16 | Package zipkin provides a monkit plugin for sending traces to Zipkin. 17 | 18 | Example usage 19 | 20 | Your main method gets set up something like this: 21 | 22 | package main 23 | 24 | import ( 25 | "net/http" 26 | 27 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2" 28 | "gopkg.in/spacemonkeygo/monkit.v2" 29 | "gopkg.in/spacemonkeygo/monkit.v2/environment" 30 | "gopkg.in/spacemonkeygo/monkit.v2/present" 31 | ) 32 | 33 | func main() { 34 | environment.Register(monkit.Default) 35 | go http.ListenAndServe("localhost:9000", present.HTTP(monkit.Default)) 36 | collector, err := zipkin.NewScribeCollector("zipkin.whatever:9042") 37 | if err != nil { 38 | panic(err) 39 | } 40 | zipkin.RegisterZipkin(monkit.Default, collector, zipkin.Options{ 41 | Fraction: 1}) 42 | 43 | ... 44 | } 45 | 46 | Once you've done that, you need to make sure your HTTP handlers pull Zipkin 47 | Context info from the Request. That's easy to do with zipkin.ContextWrapper. 48 | 49 | func HandleRequest(ctx context.Context, w http.ResponseWriter, 50 | r *http.Request) { 51 | defer mon.Task()(&ctx)(nil) 52 | 53 | ... whatever 54 | } 55 | 56 | func DoTheThing(ctx context.Context) (err error) { 57 | defer mon.Task()(&ctx)(&err) 58 | return http.Serve(listener, zipkin.ContextWrapper( 59 | zipkin.TraceHandler(zipkin.ContextHTTPHandlerFunc(HandleRequest)))) 60 | } 61 | 62 | Last, your outbound HTTP requests need to pass through Context info: 63 | 64 | func MakeRequest(ctx context.Context) (err error) { 65 | defer mon.Task()(&ctx)(&err) 66 | req, err := http.NewRequest(...) 67 | if err != nil { 68 | return err 69 | } 70 | resp, err := zipkin.TraceRequest(ctx, http.DefaultClient, req) 71 | ... 72 | } 73 | */ 74 | package zipkin // import "gopkg.in/spacemonkeygo/monkit-zipkin.v2" 75 | -------------------------------------------------------------------------------- /gen-go/scribe/GoUnusedProtection__.go: -------------------------------------------------------------------------------- 1 | // Autogenerated by Thrift Compiler (0.12.0) 2 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 3 | 4 | package scribe 5 | 6 | var GoUnusedProtection__ int; 7 | 8 | -------------------------------------------------------------------------------- /gen-go/scribe/scribe-consts.go: -------------------------------------------------------------------------------- 1 | // Autogenerated by Thrift Compiler (0.12.0) 2 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 3 | 4 | package scribe 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "reflect" 10 | "fmt" 11 | "github.com/apache/thrift/lib/go/thrift" 12 | ) 13 | 14 | // (needed to ensure safety because of naive import list construction.) 15 | var _ = thrift.ZERO 16 | var _ = fmt.Printf 17 | var _ = context.Background 18 | var _ = reflect.DeepEqual 19 | var _ = bytes.Equal 20 | 21 | 22 | func init() { 23 | } 24 | 25 | -------------------------------------------------------------------------------- /gen-go/scribe/scribe-remote/scribe-remote.go: -------------------------------------------------------------------------------- 1 | // Autogenerated by Thrift Compiler (0.12.0) 2 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 3 | 4 | package main 5 | 6 | import ( 7 | "context" 8 | "flag" 9 | "fmt" 10 | "math" 11 | "net" 12 | "net/url" 13 | "os" 14 | "strconv" 15 | "strings" 16 | 17 | "github.com/apache/thrift/lib/go/thrift" 18 | 19 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2/gen-go/scribe" 20 | ) 21 | 22 | func Usage() { 23 | fmt.Fprintln(os.Stderr, "Usage of ", os.Args[0], " [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:") 24 | flag.PrintDefaults() 25 | fmt.Fprintln(os.Stderr, "\nFunctions:") 26 | fmt.Fprintln(os.Stderr, " ResultCode Log( messages)") 27 | fmt.Fprintln(os.Stderr) 28 | os.Exit(0) 29 | } 30 | 31 | type httpHeaders map[string]string 32 | 33 | func (h httpHeaders) String() string { 34 | var m map[string]string = h 35 | return fmt.Sprintf("%s", m) 36 | } 37 | 38 | func (h httpHeaders) Set(value string) error { 39 | parts := strings.Split(value, ": ") 40 | if len(parts) != 2 { 41 | return fmt.Errorf("header should be of format 'Key: Value'") 42 | } 43 | h[parts[0]] = parts[1] 44 | return nil 45 | } 46 | 47 | func main() { 48 | flag.Usage = Usage 49 | var host string 50 | var port int 51 | var protocol string 52 | var urlString string 53 | var framed bool 54 | var useHttp bool 55 | headers := make(httpHeaders) 56 | var parsedUrl *url.URL 57 | var trans thrift.TTransport 58 | _ = strconv.Atoi 59 | _ = math.Abs 60 | flag.Usage = Usage 61 | flag.StringVar(&host, "h", "localhost", "Specify host and port") 62 | flag.IntVar(&port, "p", 9090, "Specify port") 63 | flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson, json)") 64 | flag.StringVar(&urlString, "u", "", "Specify the url") 65 | flag.BoolVar(&framed, "framed", false, "Use framed transport") 66 | flag.BoolVar(&useHttp, "http", false, "Use http") 67 | flag.Var(headers, "H", "Headers to set on the http(s) request (e.g. -H \"Key: Value\")") 68 | flag.Parse() 69 | 70 | if len(urlString) > 0 { 71 | var err error 72 | parsedUrl, err = url.Parse(urlString) 73 | if err != nil { 74 | fmt.Fprintln(os.Stderr, "Error parsing URL: ", err) 75 | flag.Usage() 76 | } 77 | host = parsedUrl.Host 78 | useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https" 79 | } else if useHttp { 80 | _, err := url.Parse(fmt.Sprint("http://", host, ":", port)) 81 | if err != nil { 82 | fmt.Fprintln(os.Stderr, "Error parsing URL: ", err) 83 | flag.Usage() 84 | } 85 | } 86 | 87 | cmd := flag.Arg(0) 88 | var err error 89 | if useHttp { 90 | trans, err = thrift.NewTHttpClient(parsedUrl.String()) 91 | if len(headers) > 0 { 92 | httptrans := trans.(*thrift.THttpClient) 93 | for key, value := range headers { 94 | httptrans.SetHeader(key, value) 95 | } 96 | } 97 | } else { 98 | portStr := fmt.Sprint(port) 99 | if strings.Contains(host, ":") { 100 | host, portStr, err = net.SplitHostPort(host) 101 | if err != nil { 102 | fmt.Fprintln(os.Stderr, "error with host:", err) 103 | os.Exit(1) 104 | } 105 | } 106 | trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr)) 107 | if err != nil { 108 | fmt.Fprintln(os.Stderr, "error resolving address:", err) 109 | os.Exit(1) 110 | } 111 | if framed { 112 | trans = thrift.NewTFramedTransport(trans) 113 | } 114 | } 115 | if err != nil { 116 | fmt.Fprintln(os.Stderr, "Error creating transport", err) 117 | os.Exit(1) 118 | } 119 | defer trans.Close() 120 | var protocolFactory thrift.TProtocolFactory 121 | switch protocol { 122 | case "compact": 123 | protocolFactory = thrift.NewTCompactProtocolFactory() 124 | break 125 | case "simplejson": 126 | protocolFactory = thrift.NewTSimpleJSONProtocolFactory() 127 | break 128 | case "json": 129 | protocolFactory = thrift.NewTJSONProtocolFactory() 130 | break 131 | case "binary", "": 132 | protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() 133 | break 134 | default: 135 | fmt.Fprintln(os.Stderr, "Invalid protocol specified: ", protocol) 136 | Usage() 137 | os.Exit(1) 138 | } 139 | iprot := protocolFactory.GetProtocol(trans) 140 | oprot := protocolFactory.GetProtocol(trans) 141 | client := scribe.NewScribeClient(thrift.NewTStandardClient(iprot, oprot)) 142 | if err := trans.Open(); err != nil { 143 | fmt.Fprintln(os.Stderr, "Error opening socket to ", host, ":", port, " ", err) 144 | os.Exit(1) 145 | } 146 | 147 | switch cmd { 148 | case "Log": 149 | if flag.NArg()-1 != 1 { 150 | fmt.Fprintln(os.Stderr, "Log requires 1 args") 151 | flag.Usage() 152 | } 153 | arg5 := flag.Arg(1) 154 | mbTrans6 := thrift.NewTMemoryBufferLen(len(arg5)) 155 | defer mbTrans6.Close() 156 | _, err7 := mbTrans6.WriteString(arg5) 157 | if err7 != nil { 158 | Usage() 159 | return 160 | } 161 | factory8 := thrift.NewTJSONProtocolFactory() 162 | jsProt9 := factory8.GetProtocol(mbTrans6) 163 | containerStruct0 := scribe.NewScribeLogArgs() 164 | err10 := containerStruct0.ReadField1(jsProt9) 165 | if err10 != nil { 166 | Usage() 167 | return 168 | } 169 | argvalue0 := containerStruct0.Messages 170 | value0 := argvalue0 171 | fmt.Print(client.Log(context.Background(), value0)) 172 | fmt.Print("\n") 173 | break 174 | case "": 175 | Usage() 176 | break 177 | default: 178 | fmt.Fprintln(os.Stderr, "Invalid function ", cmd) 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /gen-go/scribe/scribe.go: -------------------------------------------------------------------------------- 1 | // Autogenerated by Thrift Compiler (0.12.0) 2 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 3 | 4 | package scribe 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "reflect" 10 | "database/sql/driver" 11 | "errors" 12 | "fmt" 13 | "github.com/apache/thrift/lib/go/thrift" 14 | ) 15 | 16 | // (needed to ensure safety because of naive import list construction.) 17 | var _ = thrift.ZERO 18 | var _ = fmt.Printf 19 | var _ = context.Background 20 | var _ = reflect.DeepEqual 21 | var _ = bytes.Equal 22 | 23 | type ResultCode int64 24 | const ( 25 | ResultCode_OK ResultCode = 0 26 | ResultCode_TRY_LATER ResultCode = 1 27 | ) 28 | 29 | func (p ResultCode) String() string { 30 | switch p { 31 | case ResultCode_OK: return "OK" 32 | case ResultCode_TRY_LATER: return "TRY_LATER" 33 | } 34 | return "" 35 | } 36 | 37 | func ResultCodeFromString(s string) (ResultCode, error) { 38 | switch s { 39 | case "OK": return ResultCode_OK, nil 40 | case "TRY_LATER": return ResultCode_TRY_LATER, nil 41 | } 42 | return ResultCode(0), fmt.Errorf("not a valid ResultCode string") 43 | } 44 | 45 | 46 | func ResultCodePtr(v ResultCode) *ResultCode { return &v } 47 | 48 | func (p ResultCode) MarshalText() ([]byte, error) { 49 | return []byte(p.String()), nil 50 | } 51 | 52 | func (p *ResultCode) UnmarshalText(text []byte) error { 53 | q, err := ResultCodeFromString(string(text)) 54 | if (err != nil) { 55 | return err 56 | } 57 | *p = q 58 | return nil 59 | } 60 | 61 | func (p *ResultCode) Scan(value interface{}) error { 62 | v, ok := value.(int64) 63 | if !ok { 64 | return errors.New("Scan value is not int64") 65 | } 66 | *p = ResultCode(v) 67 | return nil 68 | } 69 | 70 | func (p * ResultCode) Value() (driver.Value, error) { 71 | if p == nil { 72 | return nil, nil 73 | } 74 | return int64(*p), nil 75 | } 76 | // Attributes: 77 | // - Category 78 | // - Message 79 | type LogEntry struct { 80 | Category string `thrift:"category,1" db:"category" json:"category"` 81 | Message string `thrift:"message,2" db:"message" json:"message"` 82 | } 83 | 84 | func NewLogEntry() *LogEntry { 85 | return &LogEntry{} 86 | } 87 | 88 | 89 | func (p *LogEntry) GetCategory() string { 90 | return p.Category 91 | } 92 | 93 | func (p *LogEntry) GetMessage() string { 94 | return p.Message 95 | } 96 | func (p *LogEntry) Read(iprot thrift.TProtocol) error { 97 | if _, err := iprot.ReadStructBegin(); err != nil { 98 | return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) 99 | } 100 | 101 | 102 | for { 103 | _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() 104 | if err != nil { 105 | return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) 106 | } 107 | if fieldTypeId == thrift.STOP { break; } 108 | switch fieldId { 109 | case 1: 110 | if fieldTypeId == thrift.STRING { 111 | if err := p.ReadField1(iprot); err != nil { 112 | return err 113 | } 114 | } else { 115 | if err := iprot.Skip(fieldTypeId); err != nil { 116 | return err 117 | } 118 | } 119 | case 2: 120 | if fieldTypeId == thrift.STRING { 121 | if err := p.ReadField2(iprot); err != nil { 122 | return err 123 | } 124 | } else { 125 | if err := iprot.Skip(fieldTypeId); err != nil { 126 | return err 127 | } 128 | } 129 | default: 130 | if err := iprot.Skip(fieldTypeId); err != nil { 131 | return err 132 | } 133 | } 134 | if err := iprot.ReadFieldEnd(); err != nil { 135 | return err 136 | } 137 | } 138 | if err := iprot.ReadStructEnd(); err != nil { 139 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 140 | } 141 | return nil 142 | } 143 | 144 | func (p *LogEntry) ReadField1(iprot thrift.TProtocol) error { 145 | if v, err := iprot.ReadString(); err != nil { 146 | return thrift.PrependError("error reading field 1: ", err) 147 | } else { 148 | p.Category = v 149 | } 150 | return nil 151 | } 152 | 153 | func (p *LogEntry) ReadField2(iprot thrift.TProtocol) error { 154 | if v, err := iprot.ReadString(); err != nil { 155 | return thrift.PrependError("error reading field 2: ", err) 156 | } else { 157 | p.Message = v 158 | } 159 | return nil 160 | } 161 | 162 | func (p *LogEntry) Write(oprot thrift.TProtocol) error { 163 | if err := oprot.WriteStructBegin("LogEntry"); err != nil { 164 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } 165 | if p != nil { 166 | if err := p.writeField1(oprot); err != nil { return err } 167 | if err := p.writeField2(oprot); err != nil { return err } 168 | } 169 | if err := oprot.WriteFieldStop(); err != nil { 170 | return thrift.PrependError("write field stop error: ", err) } 171 | if err := oprot.WriteStructEnd(); err != nil { 172 | return thrift.PrependError("write struct stop error: ", err) } 173 | return nil 174 | } 175 | 176 | func (p *LogEntry) writeField1(oprot thrift.TProtocol) (err error) { 177 | if err := oprot.WriteFieldBegin("category", thrift.STRING, 1); err != nil { 178 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:category: ", p), err) } 179 | if err := oprot.WriteString(string(p.Category)); err != nil { 180 | return thrift.PrependError(fmt.Sprintf("%T.category (1) field write error: ", p), err) } 181 | if err := oprot.WriteFieldEnd(); err != nil { 182 | return thrift.PrependError(fmt.Sprintf("%T write field end error 1:category: ", p), err) } 183 | return err 184 | } 185 | 186 | func (p *LogEntry) writeField2(oprot thrift.TProtocol) (err error) { 187 | if err := oprot.WriteFieldBegin("message", thrift.STRING, 2); err != nil { 188 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:message: ", p), err) } 189 | if err := oprot.WriteString(string(p.Message)); err != nil { 190 | return thrift.PrependError(fmt.Sprintf("%T.message (2) field write error: ", p), err) } 191 | if err := oprot.WriteFieldEnd(); err != nil { 192 | return thrift.PrependError(fmt.Sprintf("%T write field end error 2:message: ", p), err) } 193 | return err 194 | } 195 | 196 | func (p *LogEntry) String() string { 197 | if p == nil { 198 | return "" 199 | } 200 | return fmt.Sprintf("LogEntry(%+v)", *p) 201 | } 202 | 203 | type Scribe interface { 204 | // Parameters: 205 | // - Messages 206 | Log(ctx context.Context, messages []*LogEntry) (r ResultCode, err error) 207 | } 208 | 209 | type ScribeClient struct { 210 | c thrift.TClient 211 | } 212 | 213 | func NewScribeClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ScribeClient { 214 | return &ScribeClient{ 215 | c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)), 216 | } 217 | } 218 | 219 | func NewScribeClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ScribeClient { 220 | return &ScribeClient{ 221 | c: thrift.NewTStandardClient(iprot, oprot), 222 | } 223 | } 224 | 225 | func NewScribeClient(c thrift.TClient) *ScribeClient { 226 | return &ScribeClient{ 227 | c: c, 228 | } 229 | } 230 | 231 | func (p *ScribeClient) Client_() thrift.TClient { 232 | return p.c 233 | } 234 | // Parameters: 235 | // - Messages 236 | func (p *ScribeClient) Log(ctx context.Context, messages []*LogEntry) (r ResultCode, err error) { 237 | var _args0 ScribeLogArgs 238 | _args0.Messages = messages 239 | var _result1 ScribeLogResult 240 | if err = p.Client_().Call(ctx, "Log", &_args0, &_result1); err != nil { 241 | return 242 | } 243 | return _result1.GetSuccess(), nil 244 | } 245 | 246 | type ScribeProcessor struct { 247 | processorMap map[string]thrift.TProcessorFunction 248 | handler Scribe 249 | } 250 | 251 | func (p *ScribeProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { 252 | p.processorMap[key] = processor 253 | } 254 | 255 | func (p *ScribeProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { 256 | processor, ok = p.processorMap[key] 257 | return processor, ok 258 | } 259 | 260 | func (p *ScribeProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { 261 | return p.processorMap 262 | } 263 | 264 | func NewScribeProcessor(handler Scribe) *ScribeProcessor { 265 | 266 | self2 := &ScribeProcessor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)} 267 | self2.processorMap["Log"] = &scribeProcessorLog{handler:handler} 268 | return self2 269 | } 270 | 271 | func (p *ScribeProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { 272 | name, _, seqId, err := iprot.ReadMessageBegin() 273 | if err != nil { return false, err } 274 | if processor, ok := p.GetProcessorFunction(name); ok { 275 | return processor.Process(ctx, seqId, iprot, oprot) 276 | } 277 | iprot.Skip(thrift.STRUCT) 278 | iprot.ReadMessageEnd() 279 | x3 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function " + name) 280 | oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) 281 | x3.Write(oprot) 282 | oprot.WriteMessageEnd() 283 | oprot.Flush(ctx) 284 | return false, x3 285 | 286 | } 287 | 288 | type scribeProcessorLog struct { 289 | handler Scribe 290 | } 291 | 292 | func (p *scribeProcessorLog) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { 293 | args := ScribeLogArgs{} 294 | if err = args.Read(iprot); err != nil { 295 | iprot.ReadMessageEnd() 296 | x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) 297 | oprot.WriteMessageBegin("Log", thrift.EXCEPTION, seqId) 298 | x.Write(oprot) 299 | oprot.WriteMessageEnd() 300 | oprot.Flush(ctx) 301 | return false, err 302 | } 303 | 304 | iprot.ReadMessageEnd() 305 | result := ScribeLogResult{} 306 | var retval ResultCode 307 | var err2 error 308 | if retval, err2 = p.handler.Log(ctx, args.Messages); err2 != nil { 309 | x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing Log: " + err2.Error()) 310 | oprot.WriteMessageBegin("Log", thrift.EXCEPTION, seqId) 311 | x.Write(oprot) 312 | oprot.WriteMessageEnd() 313 | oprot.Flush(ctx) 314 | return true, err2 315 | } else { 316 | result.Success = &retval 317 | } 318 | if err2 = oprot.WriteMessageBegin("Log", thrift.REPLY, seqId); err2 != nil { 319 | err = err2 320 | } 321 | if err2 = result.Write(oprot); err == nil && err2 != nil { 322 | err = err2 323 | } 324 | if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { 325 | err = err2 326 | } 327 | if err2 = oprot.Flush(ctx); err == nil && err2 != nil { 328 | err = err2 329 | } 330 | if err != nil { 331 | return 332 | } 333 | return true, err 334 | } 335 | 336 | 337 | // HELPER FUNCTIONS AND STRUCTURES 338 | 339 | // Attributes: 340 | // - Messages 341 | type ScribeLogArgs struct { 342 | Messages []*LogEntry `thrift:"messages,1" db:"messages" json:"messages"` 343 | } 344 | 345 | func NewScribeLogArgs() *ScribeLogArgs { 346 | return &ScribeLogArgs{} 347 | } 348 | 349 | 350 | func (p *ScribeLogArgs) GetMessages() []*LogEntry { 351 | return p.Messages 352 | } 353 | func (p *ScribeLogArgs) Read(iprot thrift.TProtocol) error { 354 | if _, err := iprot.ReadStructBegin(); err != nil { 355 | return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) 356 | } 357 | 358 | 359 | for { 360 | _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() 361 | if err != nil { 362 | return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) 363 | } 364 | if fieldTypeId == thrift.STOP { break; } 365 | switch fieldId { 366 | case 1: 367 | if fieldTypeId == thrift.LIST { 368 | if err := p.ReadField1(iprot); err != nil { 369 | return err 370 | } 371 | } else { 372 | if err := iprot.Skip(fieldTypeId); err != nil { 373 | return err 374 | } 375 | } 376 | default: 377 | if err := iprot.Skip(fieldTypeId); err != nil { 378 | return err 379 | } 380 | } 381 | if err := iprot.ReadFieldEnd(); err != nil { 382 | return err 383 | } 384 | } 385 | if err := iprot.ReadStructEnd(); err != nil { 386 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 387 | } 388 | return nil 389 | } 390 | 391 | func (p *ScribeLogArgs) ReadField1(iprot thrift.TProtocol) error { 392 | _, size, err := iprot.ReadListBegin() 393 | if err != nil { 394 | return thrift.PrependError("error reading list begin: ", err) 395 | } 396 | tSlice := make([]*LogEntry, 0, size) 397 | p.Messages = tSlice 398 | for i := 0; i < size; i ++ { 399 | _elem4 := &LogEntry{} 400 | if err := _elem4.Read(iprot); err != nil { 401 | return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem4), err) 402 | } 403 | p.Messages = append(p.Messages, _elem4) 404 | } 405 | if err := iprot.ReadListEnd(); err != nil { 406 | return thrift.PrependError("error reading list end: ", err) 407 | } 408 | return nil 409 | } 410 | 411 | func (p *ScribeLogArgs) Write(oprot thrift.TProtocol) error { 412 | if err := oprot.WriteStructBegin("Log_args"); err != nil { 413 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } 414 | if p != nil { 415 | if err := p.writeField1(oprot); err != nil { return err } 416 | } 417 | if err := oprot.WriteFieldStop(); err != nil { 418 | return thrift.PrependError("write field stop error: ", err) } 419 | if err := oprot.WriteStructEnd(); err != nil { 420 | return thrift.PrependError("write struct stop error: ", err) } 421 | return nil 422 | } 423 | 424 | func (p *ScribeLogArgs) writeField1(oprot thrift.TProtocol) (err error) { 425 | if err := oprot.WriteFieldBegin("messages", thrift.LIST, 1); err != nil { 426 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:messages: ", p), err) } 427 | if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Messages)); err != nil { 428 | return thrift.PrependError("error writing list begin: ", err) 429 | } 430 | for _, v := range p.Messages { 431 | if err := v.Write(oprot); err != nil { 432 | return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) 433 | } 434 | } 435 | if err := oprot.WriteListEnd(); err != nil { 436 | return thrift.PrependError("error writing list end: ", err) 437 | } 438 | if err := oprot.WriteFieldEnd(); err != nil { 439 | return thrift.PrependError(fmt.Sprintf("%T write field end error 1:messages: ", p), err) } 440 | return err 441 | } 442 | 443 | func (p *ScribeLogArgs) String() string { 444 | if p == nil { 445 | return "" 446 | } 447 | return fmt.Sprintf("ScribeLogArgs(%+v)", *p) 448 | } 449 | 450 | // Attributes: 451 | // - Success 452 | type ScribeLogResult struct { 453 | Success *ResultCode `thrift:"success,0" db:"success" json:"success,omitempty"` 454 | } 455 | 456 | func NewScribeLogResult() *ScribeLogResult { 457 | return &ScribeLogResult{} 458 | } 459 | 460 | var ScribeLogResult_Success_DEFAULT ResultCode 461 | func (p *ScribeLogResult) GetSuccess() ResultCode { 462 | if !p.IsSetSuccess() { 463 | return ScribeLogResult_Success_DEFAULT 464 | } 465 | return *p.Success 466 | } 467 | func (p *ScribeLogResult) IsSetSuccess() bool { 468 | return p.Success != nil 469 | } 470 | 471 | func (p *ScribeLogResult) Read(iprot thrift.TProtocol) error { 472 | if _, err := iprot.ReadStructBegin(); err != nil { 473 | return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) 474 | } 475 | 476 | 477 | for { 478 | _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() 479 | if err != nil { 480 | return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) 481 | } 482 | if fieldTypeId == thrift.STOP { break; } 483 | switch fieldId { 484 | case 0: 485 | if fieldTypeId == thrift.I32 { 486 | if err := p.ReadField0(iprot); err != nil { 487 | return err 488 | } 489 | } else { 490 | if err := iprot.Skip(fieldTypeId); err != nil { 491 | return err 492 | } 493 | } 494 | default: 495 | if err := iprot.Skip(fieldTypeId); err != nil { 496 | return err 497 | } 498 | } 499 | if err := iprot.ReadFieldEnd(); err != nil { 500 | return err 501 | } 502 | } 503 | if err := iprot.ReadStructEnd(); err != nil { 504 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 505 | } 506 | return nil 507 | } 508 | 509 | func (p *ScribeLogResult) ReadField0(iprot thrift.TProtocol) error { 510 | if v, err := iprot.ReadI32(); err != nil { 511 | return thrift.PrependError("error reading field 0: ", err) 512 | } else { 513 | temp := ResultCode(v) 514 | p.Success = &temp 515 | } 516 | return nil 517 | } 518 | 519 | func (p *ScribeLogResult) Write(oprot thrift.TProtocol) error { 520 | if err := oprot.WriteStructBegin("Log_result"); err != nil { 521 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } 522 | if p != nil { 523 | if err := p.writeField0(oprot); err != nil { return err } 524 | } 525 | if err := oprot.WriteFieldStop(); err != nil { 526 | return thrift.PrependError("write field stop error: ", err) } 527 | if err := oprot.WriteStructEnd(); err != nil { 528 | return thrift.PrependError("write struct stop error: ", err) } 529 | return nil 530 | } 531 | 532 | func (p *ScribeLogResult) writeField0(oprot thrift.TProtocol) (err error) { 533 | if p.IsSetSuccess() { 534 | if err := oprot.WriteFieldBegin("success", thrift.I32, 0); err != nil { 535 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) } 536 | if err := oprot.WriteI32(int32(*p.Success)); err != nil { 537 | return thrift.PrependError(fmt.Sprintf("%T.success (0) field write error: ", p), err) } 538 | if err := oprot.WriteFieldEnd(); err != nil { 539 | return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) } 540 | } 541 | return err 542 | } 543 | 544 | func (p *ScribeLogResult) String() string { 545 | if p == nil { 546 | return "" 547 | } 548 | return fmt.Sprintf("ScribeLogResult(%+v)", *p) 549 | } 550 | 551 | 552 | -------------------------------------------------------------------------------- /gen-go/zipkin/GoUnusedProtection__.go: -------------------------------------------------------------------------------- 1 | // Autogenerated by Thrift Compiler (0.12.0) 2 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 3 | 4 | package zipkin 5 | 6 | var GoUnusedProtection__ int; 7 | 8 | -------------------------------------------------------------------------------- /gen-go/zipkin/zipkin-consts.go: -------------------------------------------------------------------------------- 1 | // Autogenerated by Thrift Compiler (0.12.0) 2 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 3 | 4 | package zipkin 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "reflect" 10 | "fmt" 11 | "github.com/apache/thrift/lib/go/thrift" 12 | ) 13 | 14 | // (needed to ensure safety because of naive import list construction.) 15 | var _ = thrift.ZERO 16 | var _ = fmt.Printf 17 | var _ = context.Background 18 | var _ = reflect.DeepEqual 19 | var _ = bytes.Equal 20 | 21 | const CLIENT_SEND = "cs" 22 | const CLIENT_RECV = "cr" 23 | const SERVER_SEND = "ss" 24 | const SERVER_RECV = "sr" 25 | 26 | func init() { 27 | } 28 | 29 | -------------------------------------------------------------------------------- /gen-go/zipkin/zipkin.go: -------------------------------------------------------------------------------- 1 | // Autogenerated by Thrift Compiler (0.12.0) 2 | // DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 3 | 4 | package zipkin 5 | 6 | import ( 7 | "bytes" 8 | "context" 9 | "reflect" 10 | "database/sql/driver" 11 | "errors" 12 | "fmt" 13 | "github.com/apache/thrift/lib/go/thrift" 14 | ) 15 | 16 | // (needed to ensure safety because of naive import list construction.) 17 | var _ = thrift.ZERO 18 | var _ = fmt.Printf 19 | var _ = context.Background 20 | var _ = reflect.DeepEqual 21 | var _ = bytes.Equal 22 | 23 | type AnnotationType int64 24 | const ( 25 | AnnotationType_BOOL AnnotationType = 0 26 | AnnotationType_BYTES AnnotationType = 1 27 | AnnotationType_I16 AnnotationType = 2 28 | AnnotationType_I32 AnnotationType = 3 29 | AnnotationType_I64 AnnotationType = 4 30 | AnnotationType_DOUBLE AnnotationType = 5 31 | AnnotationType_STRING AnnotationType = 6 32 | ) 33 | 34 | func (p AnnotationType) String() string { 35 | switch p { 36 | case AnnotationType_BOOL: return "BOOL" 37 | case AnnotationType_BYTES: return "BYTES" 38 | case AnnotationType_I16: return "I16" 39 | case AnnotationType_I32: return "I32" 40 | case AnnotationType_I64: return "I64" 41 | case AnnotationType_DOUBLE: return "DOUBLE" 42 | case AnnotationType_STRING: return "STRING" 43 | } 44 | return "" 45 | } 46 | 47 | func AnnotationTypeFromString(s string) (AnnotationType, error) { 48 | switch s { 49 | case "BOOL": return AnnotationType_BOOL, nil 50 | case "BYTES": return AnnotationType_BYTES, nil 51 | case "I16": return AnnotationType_I16, nil 52 | case "I32": return AnnotationType_I32, nil 53 | case "I64": return AnnotationType_I64, nil 54 | case "DOUBLE": return AnnotationType_DOUBLE, nil 55 | case "STRING": return AnnotationType_STRING, nil 56 | } 57 | return AnnotationType(0), fmt.Errorf("not a valid AnnotationType string") 58 | } 59 | 60 | 61 | func AnnotationTypePtr(v AnnotationType) *AnnotationType { return &v } 62 | 63 | func (p AnnotationType) MarshalText() ([]byte, error) { 64 | return []byte(p.String()), nil 65 | } 66 | 67 | func (p *AnnotationType) UnmarshalText(text []byte) error { 68 | q, err := AnnotationTypeFromString(string(text)) 69 | if (err != nil) { 70 | return err 71 | } 72 | *p = q 73 | return nil 74 | } 75 | 76 | func (p *AnnotationType) Scan(value interface{}) error { 77 | v, ok := value.(int64) 78 | if !ok { 79 | return errors.New("Scan value is not int64") 80 | } 81 | *p = AnnotationType(v) 82 | return nil 83 | } 84 | 85 | func (p * AnnotationType) Value() (driver.Value, error) { 86 | if p == nil { 87 | return nil, nil 88 | } 89 | return int64(*p), nil 90 | } 91 | // Attributes: 92 | // - Ipv4 93 | // - Port 94 | // - ServiceName 95 | type Endpoint struct { 96 | Ipv4 int32 `thrift:"ipv4,1" db:"ipv4" json:"ipv4"` 97 | Port int16 `thrift:"port,2" db:"port" json:"port"` 98 | ServiceName string `thrift:"service_name,3" db:"service_name" json:"service_name"` 99 | } 100 | 101 | func NewEndpoint() *Endpoint { 102 | return &Endpoint{} 103 | } 104 | 105 | 106 | func (p *Endpoint) GetIpv4() int32 { 107 | return p.Ipv4 108 | } 109 | 110 | func (p *Endpoint) GetPort() int16 { 111 | return p.Port 112 | } 113 | 114 | func (p *Endpoint) GetServiceName() string { 115 | return p.ServiceName 116 | } 117 | func (p *Endpoint) Read(iprot thrift.TProtocol) error { 118 | if _, err := iprot.ReadStructBegin(); err != nil { 119 | return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) 120 | } 121 | 122 | 123 | for { 124 | _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() 125 | if err != nil { 126 | return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) 127 | } 128 | if fieldTypeId == thrift.STOP { break; } 129 | switch fieldId { 130 | case 1: 131 | if fieldTypeId == thrift.I32 { 132 | if err := p.ReadField1(iprot); err != nil { 133 | return err 134 | } 135 | } else { 136 | if err := iprot.Skip(fieldTypeId); err != nil { 137 | return err 138 | } 139 | } 140 | case 2: 141 | if fieldTypeId == thrift.I16 { 142 | if err := p.ReadField2(iprot); err != nil { 143 | return err 144 | } 145 | } else { 146 | if err := iprot.Skip(fieldTypeId); err != nil { 147 | return err 148 | } 149 | } 150 | case 3: 151 | if fieldTypeId == thrift.STRING { 152 | if err := p.ReadField3(iprot); err != nil { 153 | return err 154 | } 155 | } else { 156 | if err := iprot.Skip(fieldTypeId); err != nil { 157 | return err 158 | } 159 | } 160 | default: 161 | if err := iprot.Skip(fieldTypeId); err != nil { 162 | return err 163 | } 164 | } 165 | if err := iprot.ReadFieldEnd(); err != nil { 166 | return err 167 | } 168 | } 169 | if err := iprot.ReadStructEnd(); err != nil { 170 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 171 | } 172 | return nil 173 | } 174 | 175 | func (p *Endpoint) ReadField1(iprot thrift.TProtocol) error { 176 | if v, err := iprot.ReadI32(); err != nil { 177 | return thrift.PrependError("error reading field 1: ", err) 178 | } else { 179 | p.Ipv4 = v 180 | } 181 | return nil 182 | } 183 | 184 | func (p *Endpoint) ReadField2(iprot thrift.TProtocol) error { 185 | if v, err := iprot.ReadI16(); err != nil { 186 | return thrift.PrependError("error reading field 2: ", err) 187 | } else { 188 | p.Port = v 189 | } 190 | return nil 191 | } 192 | 193 | func (p *Endpoint) ReadField3(iprot thrift.TProtocol) error { 194 | if v, err := iprot.ReadString(); err != nil { 195 | return thrift.PrependError("error reading field 3: ", err) 196 | } else { 197 | p.ServiceName = v 198 | } 199 | return nil 200 | } 201 | 202 | func (p *Endpoint) Write(oprot thrift.TProtocol) error { 203 | if err := oprot.WriteStructBegin("Endpoint"); err != nil { 204 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } 205 | if p != nil { 206 | if err := p.writeField1(oprot); err != nil { return err } 207 | if err := p.writeField2(oprot); err != nil { return err } 208 | if err := p.writeField3(oprot); err != nil { return err } 209 | } 210 | if err := oprot.WriteFieldStop(); err != nil { 211 | return thrift.PrependError("write field stop error: ", err) } 212 | if err := oprot.WriteStructEnd(); err != nil { 213 | return thrift.PrependError("write struct stop error: ", err) } 214 | return nil 215 | } 216 | 217 | func (p *Endpoint) writeField1(oprot thrift.TProtocol) (err error) { 218 | if err := oprot.WriteFieldBegin("ipv4", thrift.I32, 1); err != nil { 219 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:ipv4: ", p), err) } 220 | if err := oprot.WriteI32(int32(p.Ipv4)); err != nil { 221 | return thrift.PrependError(fmt.Sprintf("%T.ipv4 (1) field write error: ", p), err) } 222 | if err := oprot.WriteFieldEnd(); err != nil { 223 | return thrift.PrependError(fmt.Sprintf("%T write field end error 1:ipv4: ", p), err) } 224 | return err 225 | } 226 | 227 | func (p *Endpoint) writeField2(oprot thrift.TProtocol) (err error) { 228 | if err := oprot.WriteFieldBegin("port", thrift.I16, 2); err != nil { 229 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:port: ", p), err) } 230 | if err := oprot.WriteI16(int16(p.Port)); err != nil { 231 | return thrift.PrependError(fmt.Sprintf("%T.port (2) field write error: ", p), err) } 232 | if err := oprot.WriteFieldEnd(); err != nil { 233 | return thrift.PrependError(fmt.Sprintf("%T write field end error 2:port: ", p), err) } 234 | return err 235 | } 236 | 237 | func (p *Endpoint) writeField3(oprot thrift.TProtocol) (err error) { 238 | if err := oprot.WriteFieldBegin("service_name", thrift.STRING, 3); err != nil { 239 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:service_name: ", p), err) } 240 | if err := oprot.WriteString(string(p.ServiceName)); err != nil { 241 | return thrift.PrependError(fmt.Sprintf("%T.service_name (3) field write error: ", p), err) } 242 | if err := oprot.WriteFieldEnd(); err != nil { 243 | return thrift.PrependError(fmt.Sprintf("%T write field end error 3:service_name: ", p), err) } 244 | return err 245 | } 246 | 247 | func (p *Endpoint) String() string { 248 | if p == nil { 249 | return "" 250 | } 251 | return fmt.Sprintf("Endpoint(%+v)", *p) 252 | } 253 | 254 | // Attributes: 255 | // - Timestamp 256 | // - Value 257 | // - Host 258 | // - Duration 259 | type Annotation struct { 260 | Timestamp int64 `thrift:"timestamp,1" db:"timestamp" json:"timestamp"` 261 | Value string `thrift:"value,2" db:"value" json:"value"` 262 | Host *Endpoint `thrift:"host,3" db:"host" json:"host,omitempty"` 263 | Duration *int32 `thrift:"duration,4" db:"duration" json:"duration,omitempty"` 264 | } 265 | 266 | func NewAnnotation() *Annotation { 267 | return &Annotation{} 268 | } 269 | 270 | 271 | func (p *Annotation) GetTimestamp() int64 { 272 | return p.Timestamp 273 | } 274 | 275 | func (p *Annotation) GetValue() string { 276 | return p.Value 277 | } 278 | var Annotation_Host_DEFAULT *Endpoint 279 | func (p *Annotation) GetHost() *Endpoint { 280 | if !p.IsSetHost() { 281 | return Annotation_Host_DEFAULT 282 | } 283 | return p.Host 284 | } 285 | var Annotation_Duration_DEFAULT int32 286 | func (p *Annotation) GetDuration() int32 { 287 | if !p.IsSetDuration() { 288 | return Annotation_Duration_DEFAULT 289 | } 290 | return *p.Duration 291 | } 292 | func (p *Annotation) IsSetHost() bool { 293 | return p.Host != nil 294 | } 295 | 296 | func (p *Annotation) IsSetDuration() bool { 297 | return p.Duration != nil 298 | } 299 | 300 | func (p *Annotation) Read(iprot thrift.TProtocol) error { 301 | if _, err := iprot.ReadStructBegin(); err != nil { 302 | return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) 303 | } 304 | 305 | 306 | for { 307 | _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() 308 | if err != nil { 309 | return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) 310 | } 311 | if fieldTypeId == thrift.STOP { break; } 312 | switch fieldId { 313 | case 1: 314 | if fieldTypeId == thrift.I64 { 315 | if err := p.ReadField1(iprot); err != nil { 316 | return err 317 | } 318 | } else { 319 | if err := iprot.Skip(fieldTypeId); err != nil { 320 | return err 321 | } 322 | } 323 | case 2: 324 | if fieldTypeId == thrift.STRING { 325 | if err := p.ReadField2(iprot); err != nil { 326 | return err 327 | } 328 | } else { 329 | if err := iprot.Skip(fieldTypeId); err != nil { 330 | return err 331 | } 332 | } 333 | case 3: 334 | if fieldTypeId == thrift.STRUCT { 335 | if err := p.ReadField3(iprot); err != nil { 336 | return err 337 | } 338 | } else { 339 | if err := iprot.Skip(fieldTypeId); err != nil { 340 | return err 341 | } 342 | } 343 | case 4: 344 | if fieldTypeId == thrift.I32 { 345 | if err := p.ReadField4(iprot); err != nil { 346 | return err 347 | } 348 | } else { 349 | if err := iprot.Skip(fieldTypeId); err != nil { 350 | return err 351 | } 352 | } 353 | default: 354 | if err := iprot.Skip(fieldTypeId); err != nil { 355 | return err 356 | } 357 | } 358 | if err := iprot.ReadFieldEnd(); err != nil { 359 | return err 360 | } 361 | } 362 | if err := iprot.ReadStructEnd(); err != nil { 363 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 364 | } 365 | return nil 366 | } 367 | 368 | func (p *Annotation) ReadField1(iprot thrift.TProtocol) error { 369 | if v, err := iprot.ReadI64(); err != nil { 370 | return thrift.PrependError("error reading field 1: ", err) 371 | } else { 372 | p.Timestamp = v 373 | } 374 | return nil 375 | } 376 | 377 | func (p *Annotation) ReadField2(iprot thrift.TProtocol) error { 378 | if v, err := iprot.ReadString(); err != nil { 379 | return thrift.PrependError("error reading field 2: ", err) 380 | } else { 381 | p.Value = v 382 | } 383 | return nil 384 | } 385 | 386 | func (p *Annotation) ReadField3(iprot thrift.TProtocol) error { 387 | p.Host = &Endpoint{} 388 | if err := p.Host.Read(iprot); err != nil { 389 | return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Host), err) 390 | } 391 | return nil 392 | } 393 | 394 | func (p *Annotation) ReadField4(iprot thrift.TProtocol) error { 395 | if v, err := iprot.ReadI32(); err != nil { 396 | return thrift.PrependError("error reading field 4: ", err) 397 | } else { 398 | p.Duration = &v 399 | } 400 | return nil 401 | } 402 | 403 | func (p *Annotation) Write(oprot thrift.TProtocol) error { 404 | if err := oprot.WriteStructBegin("Annotation"); err != nil { 405 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } 406 | if p != nil { 407 | if err := p.writeField1(oprot); err != nil { return err } 408 | if err := p.writeField2(oprot); err != nil { return err } 409 | if err := p.writeField3(oprot); err != nil { return err } 410 | if err := p.writeField4(oprot); err != nil { return err } 411 | } 412 | if err := oprot.WriteFieldStop(); err != nil { 413 | return thrift.PrependError("write field stop error: ", err) } 414 | if err := oprot.WriteStructEnd(); err != nil { 415 | return thrift.PrependError("write struct stop error: ", err) } 416 | return nil 417 | } 418 | 419 | func (p *Annotation) writeField1(oprot thrift.TProtocol) (err error) { 420 | if err := oprot.WriteFieldBegin("timestamp", thrift.I64, 1); err != nil { 421 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:timestamp: ", p), err) } 422 | if err := oprot.WriteI64(int64(p.Timestamp)); err != nil { 423 | return thrift.PrependError(fmt.Sprintf("%T.timestamp (1) field write error: ", p), err) } 424 | if err := oprot.WriteFieldEnd(); err != nil { 425 | return thrift.PrependError(fmt.Sprintf("%T write field end error 1:timestamp: ", p), err) } 426 | return err 427 | } 428 | 429 | func (p *Annotation) writeField2(oprot thrift.TProtocol) (err error) { 430 | if err := oprot.WriteFieldBegin("value", thrift.STRING, 2); err != nil { 431 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:value: ", p), err) } 432 | if err := oprot.WriteString(string(p.Value)); err != nil { 433 | return thrift.PrependError(fmt.Sprintf("%T.value (2) field write error: ", p), err) } 434 | if err := oprot.WriteFieldEnd(); err != nil { 435 | return thrift.PrependError(fmt.Sprintf("%T write field end error 2:value: ", p), err) } 436 | return err 437 | } 438 | 439 | func (p *Annotation) writeField3(oprot thrift.TProtocol) (err error) { 440 | if p.IsSetHost() { 441 | if err := oprot.WriteFieldBegin("host", thrift.STRUCT, 3); err != nil { 442 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:host: ", p), err) } 443 | if err := p.Host.Write(oprot); err != nil { 444 | return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Host), err) 445 | } 446 | if err := oprot.WriteFieldEnd(); err != nil { 447 | return thrift.PrependError(fmt.Sprintf("%T write field end error 3:host: ", p), err) } 448 | } 449 | return err 450 | } 451 | 452 | func (p *Annotation) writeField4(oprot thrift.TProtocol) (err error) { 453 | if p.IsSetDuration() { 454 | if err := oprot.WriteFieldBegin("duration", thrift.I32, 4); err != nil { 455 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:duration: ", p), err) } 456 | if err := oprot.WriteI32(int32(*p.Duration)); err != nil { 457 | return thrift.PrependError(fmt.Sprintf("%T.duration (4) field write error: ", p), err) } 458 | if err := oprot.WriteFieldEnd(); err != nil { 459 | return thrift.PrependError(fmt.Sprintf("%T write field end error 4:duration: ", p), err) } 460 | } 461 | return err 462 | } 463 | 464 | func (p *Annotation) String() string { 465 | if p == nil { 466 | return "" 467 | } 468 | return fmt.Sprintf("Annotation(%+v)", *p) 469 | } 470 | 471 | // Attributes: 472 | // - Key 473 | // - Value 474 | // - AnnotationType 475 | // - Host 476 | type BinaryAnnotation struct { 477 | Key string `thrift:"key,1" db:"key" json:"key"` 478 | Value []byte `thrift:"value,2" db:"value" json:"value"` 479 | AnnotationType AnnotationType `thrift:"annotation_type,3" db:"annotation_type" json:"annotation_type"` 480 | Host *Endpoint `thrift:"host,4" db:"host" json:"host,omitempty"` 481 | } 482 | 483 | func NewBinaryAnnotation() *BinaryAnnotation { 484 | return &BinaryAnnotation{} 485 | } 486 | 487 | 488 | func (p *BinaryAnnotation) GetKey() string { 489 | return p.Key 490 | } 491 | 492 | func (p *BinaryAnnotation) GetValue() []byte { 493 | return p.Value 494 | } 495 | 496 | func (p *BinaryAnnotation) GetAnnotationType() AnnotationType { 497 | return p.AnnotationType 498 | } 499 | var BinaryAnnotation_Host_DEFAULT *Endpoint 500 | func (p *BinaryAnnotation) GetHost() *Endpoint { 501 | if !p.IsSetHost() { 502 | return BinaryAnnotation_Host_DEFAULT 503 | } 504 | return p.Host 505 | } 506 | func (p *BinaryAnnotation) IsSetHost() bool { 507 | return p.Host != nil 508 | } 509 | 510 | func (p *BinaryAnnotation) Read(iprot thrift.TProtocol) error { 511 | if _, err := iprot.ReadStructBegin(); err != nil { 512 | return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) 513 | } 514 | 515 | 516 | for { 517 | _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() 518 | if err != nil { 519 | return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) 520 | } 521 | if fieldTypeId == thrift.STOP { break; } 522 | switch fieldId { 523 | case 1: 524 | if fieldTypeId == thrift.STRING { 525 | if err := p.ReadField1(iprot); err != nil { 526 | return err 527 | } 528 | } else { 529 | if err := iprot.Skip(fieldTypeId); err != nil { 530 | return err 531 | } 532 | } 533 | case 2: 534 | if fieldTypeId == thrift.STRING { 535 | if err := p.ReadField2(iprot); err != nil { 536 | return err 537 | } 538 | } else { 539 | if err := iprot.Skip(fieldTypeId); err != nil { 540 | return err 541 | } 542 | } 543 | case 3: 544 | if fieldTypeId == thrift.I32 { 545 | if err := p.ReadField3(iprot); err != nil { 546 | return err 547 | } 548 | } else { 549 | if err := iprot.Skip(fieldTypeId); err != nil { 550 | return err 551 | } 552 | } 553 | case 4: 554 | if fieldTypeId == thrift.STRUCT { 555 | if err := p.ReadField4(iprot); err != nil { 556 | return err 557 | } 558 | } else { 559 | if err := iprot.Skip(fieldTypeId); err != nil { 560 | return err 561 | } 562 | } 563 | default: 564 | if err := iprot.Skip(fieldTypeId); err != nil { 565 | return err 566 | } 567 | } 568 | if err := iprot.ReadFieldEnd(); err != nil { 569 | return err 570 | } 571 | } 572 | if err := iprot.ReadStructEnd(); err != nil { 573 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 574 | } 575 | return nil 576 | } 577 | 578 | func (p *BinaryAnnotation) ReadField1(iprot thrift.TProtocol) error { 579 | if v, err := iprot.ReadString(); err != nil { 580 | return thrift.PrependError("error reading field 1: ", err) 581 | } else { 582 | p.Key = v 583 | } 584 | return nil 585 | } 586 | 587 | func (p *BinaryAnnotation) ReadField2(iprot thrift.TProtocol) error { 588 | if v, err := iprot.ReadBinary(); err != nil { 589 | return thrift.PrependError("error reading field 2: ", err) 590 | } else { 591 | p.Value = v 592 | } 593 | return nil 594 | } 595 | 596 | func (p *BinaryAnnotation) ReadField3(iprot thrift.TProtocol) error { 597 | if v, err := iprot.ReadI32(); err != nil { 598 | return thrift.PrependError("error reading field 3: ", err) 599 | } else { 600 | temp := AnnotationType(v) 601 | p.AnnotationType = temp 602 | } 603 | return nil 604 | } 605 | 606 | func (p *BinaryAnnotation) ReadField4(iprot thrift.TProtocol) error { 607 | p.Host = &Endpoint{} 608 | if err := p.Host.Read(iprot); err != nil { 609 | return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Host), err) 610 | } 611 | return nil 612 | } 613 | 614 | func (p *BinaryAnnotation) Write(oprot thrift.TProtocol) error { 615 | if err := oprot.WriteStructBegin("BinaryAnnotation"); err != nil { 616 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } 617 | if p != nil { 618 | if err := p.writeField1(oprot); err != nil { return err } 619 | if err := p.writeField2(oprot); err != nil { return err } 620 | if err := p.writeField3(oprot); err != nil { return err } 621 | if err := p.writeField4(oprot); err != nil { return err } 622 | } 623 | if err := oprot.WriteFieldStop(); err != nil { 624 | return thrift.PrependError("write field stop error: ", err) } 625 | if err := oprot.WriteStructEnd(); err != nil { 626 | return thrift.PrependError("write struct stop error: ", err) } 627 | return nil 628 | } 629 | 630 | func (p *BinaryAnnotation) writeField1(oprot thrift.TProtocol) (err error) { 631 | if err := oprot.WriteFieldBegin("key", thrift.STRING, 1); err != nil { 632 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:key: ", p), err) } 633 | if err := oprot.WriteString(string(p.Key)); err != nil { 634 | return thrift.PrependError(fmt.Sprintf("%T.key (1) field write error: ", p), err) } 635 | if err := oprot.WriteFieldEnd(); err != nil { 636 | return thrift.PrependError(fmt.Sprintf("%T write field end error 1:key: ", p), err) } 637 | return err 638 | } 639 | 640 | func (p *BinaryAnnotation) writeField2(oprot thrift.TProtocol) (err error) { 641 | if err := oprot.WriteFieldBegin("value", thrift.STRING, 2); err != nil { 642 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:value: ", p), err) } 643 | if err := oprot.WriteBinary(p.Value); err != nil { 644 | return thrift.PrependError(fmt.Sprintf("%T.value (2) field write error: ", p), err) } 645 | if err := oprot.WriteFieldEnd(); err != nil { 646 | return thrift.PrependError(fmt.Sprintf("%T write field end error 2:value: ", p), err) } 647 | return err 648 | } 649 | 650 | func (p *BinaryAnnotation) writeField3(oprot thrift.TProtocol) (err error) { 651 | if err := oprot.WriteFieldBegin("annotation_type", thrift.I32, 3); err != nil { 652 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:annotation_type: ", p), err) } 653 | if err := oprot.WriteI32(int32(p.AnnotationType)); err != nil { 654 | return thrift.PrependError(fmt.Sprintf("%T.annotation_type (3) field write error: ", p), err) } 655 | if err := oprot.WriteFieldEnd(); err != nil { 656 | return thrift.PrependError(fmt.Sprintf("%T write field end error 3:annotation_type: ", p), err) } 657 | return err 658 | } 659 | 660 | func (p *BinaryAnnotation) writeField4(oprot thrift.TProtocol) (err error) { 661 | if p.IsSetHost() { 662 | if err := oprot.WriteFieldBegin("host", thrift.STRUCT, 4); err != nil { 663 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:host: ", p), err) } 664 | if err := p.Host.Write(oprot); err != nil { 665 | return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Host), err) 666 | } 667 | if err := oprot.WriteFieldEnd(); err != nil { 668 | return thrift.PrependError(fmt.Sprintf("%T write field end error 4:host: ", p), err) } 669 | } 670 | return err 671 | } 672 | 673 | func (p *BinaryAnnotation) String() string { 674 | if p == nil { 675 | return "" 676 | } 677 | return fmt.Sprintf("BinaryAnnotation(%+v)", *p) 678 | } 679 | 680 | // Attributes: 681 | // - TraceID 682 | // - Name 683 | // - ID 684 | // - ParentID 685 | // - Annotations 686 | // - BinaryAnnotations 687 | // - Debug 688 | type Span struct { 689 | TraceID int64 `thrift:"trace_id,1" db:"trace_id" json:"trace_id"` 690 | // unused field # 2 691 | Name string `thrift:"name,3" db:"name" json:"name"` 692 | ID int64 `thrift:"id,4" db:"id" json:"id"` 693 | ParentID *int64 `thrift:"parent_id,5" db:"parent_id" json:"parent_id,omitempty"` 694 | Annotations []*Annotation `thrift:"annotations,6" db:"annotations" json:"annotations"` 695 | // unused field # 7 696 | BinaryAnnotations []*BinaryAnnotation `thrift:"binary_annotations,8" db:"binary_annotations" json:"binary_annotations"` 697 | Debug bool `thrift:"debug,9" db:"debug" json:"debug,omitempty"` 698 | } 699 | 700 | func NewSpan() *Span { 701 | return &Span{} 702 | } 703 | 704 | 705 | func (p *Span) GetTraceID() int64 { 706 | return p.TraceID 707 | } 708 | 709 | func (p *Span) GetName() string { 710 | return p.Name 711 | } 712 | 713 | func (p *Span) GetID() int64 { 714 | return p.ID 715 | } 716 | var Span_ParentID_DEFAULT int64 717 | func (p *Span) GetParentID() int64 { 718 | if !p.IsSetParentID() { 719 | return Span_ParentID_DEFAULT 720 | } 721 | return *p.ParentID 722 | } 723 | 724 | func (p *Span) GetAnnotations() []*Annotation { 725 | return p.Annotations 726 | } 727 | 728 | func (p *Span) GetBinaryAnnotations() []*BinaryAnnotation { 729 | return p.BinaryAnnotations 730 | } 731 | var Span_Debug_DEFAULT bool = false 732 | 733 | func (p *Span) GetDebug() bool { 734 | return p.Debug 735 | } 736 | func (p *Span) IsSetParentID() bool { 737 | return p.ParentID != nil 738 | } 739 | 740 | func (p *Span) IsSetDebug() bool { 741 | return p.Debug != Span_Debug_DEFAULT 742 | } 743 | 744 | func (p *Span) Read(iprot thrift.TProtocol) error { 745 | if _, err := iprot.ReadStructBegin(); err != nil { 746 | return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) 747 | } 748 | 749 | 750 | for { 751 | _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() 752 | if err != nil { 753 | return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) 754 | } 755 | if fieldTypeId == thrift.STOP { break; } 756 | switch fieldId { 757 | case 1: 758 | if fieldTypeId == thrift.I64 { 759 | if err := p.ReadField1(iprot); err != nil { 760 | return err 761 | } 762 | } else { 763 | if err := iprot.Skip(fieldTypeId); err != nil { 764 | return err 765 | } 766 | } 767 | case 3: 768 | if fieldTypeId == thrift.STRING { 769 | if err := p.ReadField3(iprot); err != nil { 770 | return err 771 | } 772 | } else { 773 | if err := iprot.Skip(fieldTypeId); err != nil { 774 | return err 775 | } 776 | } 777 | case 4: 778 | if fieldTypeId == thrift.I64 { 779 | if err := p.ReadField4(iprot); err != nil { 780 | return err 781 | } 782 | } else { 783 | if err := iprot.Skip(fieldTypeId); err != nil { 784 | return err 785 | } 786 | } 787 | case 5: 788 | if fieldTypeId == thrift.I64 { 789 | if err := p.ReadField5(iprot); err != nil { 790 | return err 791 | } 792 | } else { 793 | if err := iprot.Skip(fieldTypeId); err != nil { 794 | return err 795 | } 796 | } 797 | case 6: 798 | if fieldTypeId == thrift.LIST { 799 | if err := p.ReadField6(iprot); err != nil { 800 | return err 801 | } 802 | } else { 803 | if err := iprot.Skip(fieldTypeId); err != nil { 804 | return err 805 | } 806 | } 807 | case 8: 808 | if fieldTypeId == thrift.LIST { 809 | if err := p.ReadField8(iprot); err != nil { 810 | return err 811 | } 812 | } else { 813 | if err := iprot.Skip(fieldTypeId); err != nil { 814 | return err 815 | } 816 | } 817 | case 9: 818 | if fieldTypeId == thrift.BOOL { 819 | if err := p.ReadField9(iprot); err != nil { 820 | return err 821 | } 822 | } else { 823 | if err := iprot.Skip(fieldTypeId); err != nil { 824 | return err 825 | } 826 | } 827 | default: 828 | if err := iprot.Skip(fieldTypeId); err != nil { 829 | return err 830 | } 831 | } 832 | if err := iprot.ReadFieldEnd(); err != nil { 833 | return err 834 | } 835 | } 836 | if err := iprot.ReadStructEnd(); err != nil { 837 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 838 | } 839 | return nil 840 | } 841 | 842 | func (p *Span) ReadField1(iprot thrift.TProtocol) error { 843 | if v, err := iprot.ReadI64(); err != nil { 844 | return thrift.PrependError("error reading field 1: ", err) 845 | } else { 846 | p.TraceID = v 847 | } 848 | return nil 849 | } 850 | 851 | func (p *Span) ReadField3(iprot thrift.TProtocol) error { 852 | if v, err := iprot.ReadString(); err != nil { 853 | return thrift.PrependError("error reading field 3: ", err) 854 | } else { 855 | p.Name = v 856 | } 857 | return nil 858 | } 859 | 860 | func (p *Span) ReadField4(iprot thrift.TProtocol) error { 861 | if v, err := iprot.ReadI64(); err != nil { 862 | return thrift.PrependError("error reading field 4: ", err) 863 | } else { 864 | p.ID = v 865 | } 866 | return nil 867 | } 868 | 869 | func (p *Span) ReadField5(iprot thrift.TProtocol) error { 870 | if v, err := iprot.ReadI64(); err != nil { 871 | return thrift.PrependError("error reading field 5: ", err) 872 | } else { 873 | p.ParentID = &v 874 | } 875 | return nil 876 | } 877 | 878 | func (p *Span) ReadField6(iprot thrift.TProtocol) error { 879 | _, size, err := iprot.ReadListBegin() 880 | if err != nil { 881 | return thrift.PrependError("error reading list begin: ", err) 882 | } 883 | tSlice := make([]*Annotation, 0, size) 884 | p.Annotations = tSlice 885 | for i := 0; i < size; i ++ { 886 | _elem0 := &Annotation{} 887 | if err := _elem0.Read(iprot); err != nil { 888 | return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem0), err) 889 | } 890 | p.Annotations = append(p.Annotations, _elem0) 891 | } 892 | if err := iprot.ReadListEnd(); err != nil { 893 | return thrift.PrependError("error reading list end: ", err) 894 | } 895 | return nil 896 | } 897 | 898 | func (p *Span) ReadField8(iprot thrift.TProtocol) error { 899 | _, size, err := iprot.ReadListBegin() 900 | if err != nil { 901 | return thrift.PrependError("error reading list begin: ", err) 902 | } 903 | tSlice := make([]*BinaryAnnotation, 0, size) 904 | p.BinaryAnnotations = tSlice 905 | for i := 0; i < size; i ++ { 906 | _elem1 := &BinaryAnnotation{} 907 | if err := _elem1.Read(iprot); err != nil { 908 | return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem1), err) 909 | } 910 | p.BinaryAnnotations = append(p.BinaryAnnotations, _elem1) 911 | } 912 | if err := iprot.ReadListEnd(); err != nil { 913 | return thrift.PrependError("error reading list end: ", err) 914 | } 915 | return nil 916 | } 917 | 918 | func (p *Span) ReadField9(iprot thrift.TProtocol) error { 919 | if v, err := iprot.ReadBool(); err != nil { 920 | return thrift.PrependError("error reading field 9: ", err) 921 | } else { 922 | p.Debug = v 923 | } 924 | return nil 925 | } 926 | 927 | func (p *Span) Write(oprot thrift.TProtocol) error { 928 | if err := oprot.WriteStructBegin("Span"); err != nil { 929 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } 930 | if p != nil { 931 | if err := p.writeField1(oprot); err != nil { return err } 932 | if err := p.writeField3(oprot); err != nil { return err } 933 | if err := p.writeField4(oprot); err != nil { return err } 934 | if err := p.writeField5(oprot); err != nil { return err } 935 | if err := p.writeField6(oprot); err != nil { return err } 936 | if err := p.writeField8(oprot); err != nil { return err } 937 | if err := p.writeField9(oprot); err != nil { return err } 938 | } 939 | if err := oprot.WriteFieldStop(); err != nil { 940 | return thrift.PrependError("write field stop error: ", err) } 941 | if err := oprot.WriteStructEnd(); err != nil { 942 | return thrift.PrependError("write struct stop error: ", err) } 943 | return nil 944 | } 945 | 946 | func (p *Span) writeField1(oprot thrift.TProtocol) (err error) { 947 | if err := oprot.WriteFieldBegin("trace_id", thrift.I64, 1); err != nil { 948 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:trace_id: ", p), err) } 949 | if err := oprot.WriteI64(int64(p.TraceID)); err != nil { 950 | return thrift.PrependError(fmt.Sprintf("%T.trace_id (1) field write error: ", p), err) } 951 | if err := oprot.WriteFieldEnd(); err != nil { 952 | return thrift.PrependError(fmt.Sprintf("%T write field end error 1:trace_id: ", p), err) } 953 | return err 954 | } 955 | 956 | func (p *Span) writeField3(oprot thrift.TProtocol) (err error) { 957 | if err := oprot.WriteFieldBegin("name", thrift.STRING, 3); err != nil { 958 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:name: ", p), err) } 959 | if err := oprot.WriteString(string(p.Name)); err != nil { 960 | return thrift.PrependError(fmt.Sprintf("%T.name (3) field write error: ", p), err) } 961 | if err := oprot.WriteFieldEnd(); err != nil { 962 | return thrift.PrependError(fmt.Sprintf("%T write field end error 3:name: ", p), err) } 963 | return err 964 | } 965 | 966 | func (p *Span) writeField4(oprot thrift.TProtocol) (err error) { 967 | if err := oprot.WriteFieldBegin("id", thrift.I64, 4); err != nil { 968 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:id: ", p), err) } 969 | if err := oprot.WriteI64(int64(p.ID)); err != nil { 970 | return thrift.PrependError(fmt.Sprintf("%T.id (4) field write error: ", p), err) } 971 | if err := oprot.WriteFieldEnd(); err != nil { 972 | return thrift.PrependError(fmt.Sprintf("%T write field end error 4:id: ", p), err) } 973 | return err 974 | } 975 | 976 | func (p *Span) writeField5(oprot thrift.TProtocol) (err error) { 977 | if p.IsSetParentID() { 978 | if err := oprot.WriteFieldBegin("parent_id", thrift.I64, 5); err != nil { 979 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:parent_id: ", p), err) } 980 | if err := oprot.WriteI64(int64(*p.ParentID)); err != nil { 981 | return thrift.PrependError(fmt.Sprintf("%T.parent_id (5) field write error: ", p), err) } 982 | if err := oprot.WriteFieldEnd(); err != nil { 983 | return thrift.PrependError(fmt.Sprintf("%T write field end error 5:parent_id: ", p), err) } 984 | } 985 | return err 986 | } 987 | 988 | func (p *Span) writeField6(oprot thrift.TProtocol) (err error) { 989 | if err := oprot.WriteFieldBegin("annotations", thrift.LIST, 6); err != nil { 990 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 6:annotations: ", p), err) } 991 | if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Annotations)); err != nil { 992 | return thrift.PrependError("error writing list begin: ", err) 993 | } 994 | for _, v := range p.Annotations { 995 | if err := v.Write(oprot); err != nil { 996 | return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) 997 | } 998 | } 999 | if err := oprot.WriteListEnd(); err != nil { 1000 | return thrift.PrependError("error writing list end: ", err) 1001 | } 1002 | if err := oprot.WriteFieldEnd(); err != nil { 1003 | return thrift.PrependError(fmt.Sprintf("%T write field end error 6:annotations: ", p), err) } 1004 | return err 1005 | } 1006 | 1007 | func (p *Span) writeField8(oprot thrift.TProtocol) (err error) { 1008 | if err := oprot.WriteFieldBegin("binary_annotations", thrift.LIST, 8); err != nil { 1009 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 8:binary_annotations: ", p), err) } 1010 | if err := oprot.WriteListBegin(thrift.STRUCT, len(p.BinaryAnnotations)); err != nil { 1011 | return thrift.PrependError("error writing list begin: ", err) 1012 | } 1013 | for _, v := range p.BinaryAnnotations { 1014 | if err := v.Write(oprot); err != nil { 1015 | return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) 1016 | } 1017 | } 1018 | if err := oprot.WriteListEnd(); err != nil { 1019 | return thrift.PrependError("error writing list end: ", err) 1020 | } 1021 | if err := oprot.WriteFieldEnd(); err != nil { 1022 | return thrift.PrependError(fmt.Sprintf("%T write field end error 8:binary_annotations: ", p), err) } 1023 | return err 1024 | } 1025 | 1026 | func (p *Span) writeField9(oprot thrift.TProtocol) (err error) { 1027 | if p.IsSetDebug() { 1028 | if err := oprot.WriteFieldBegin("debug", thrift.BOOL, 9); err != nil { 1029 | return thrift.PrependError(fmt.Sprintf("%T write field begin error 9:debug: ", p), err) } 1030 | if err := oprot.WriteBool(bool(p.Debug)); err != nil { 1031 | return thrift.PrependError(fmt.Sprintf("%T.debug (9) field write error: ", p), err) } 1032 | if err := oprot.WriteFieldEnd(); err != nil { 1033 | return thrift.PrependError(fmt.Sprintf("%T write field end error 9:debug: ", p), err) } 1034 | } 1035 | return err 1036 | } 1037 | 1038 | func (p *Span) String() string { 1039 | if p == nil { 1040 | return "" 1041 | } 1042 | return fmt.Sprintf("Span(%+v)", *p) 1043 | } 1044 | 1045 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module gopkg.in/spacemonkeygo/monkit-zipkin.v2 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/apache/thrift v0.12.0 7 | github.com/spacemonkeygo/errors v0.0.0-20171212215202-9064522e9fd1 8 | gopkg.in/spacemonkeygo/monkit.v2 v2.0.0-20180827161543-6ebf5a752f9b 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs= 2 | github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 3 | github.com/spacemonkeygo/errors v0.0.0-20171212215202-9064522e9fd1 h1:xHQewZjohU9/wUsyC99navCjQDNHtTgUOM/J1jAbzfw= 4 | github.com/spacemonkeygo/errors v0.0.0-20171212215202-9064522e9fd1/go.mod h1:7NL9UAYQnRM5iKHUCld3tf02fKb5Dft+41+VckASUy0= 5 | github.com/spacemonkeygo/monotime v0.0.0-20180824235756-e3f48a95f98a h1:8+cCjxhToanKmxLIbuyBNe2EnpgwhiivsIaRJstDRFA= 6 | github.com/spacemonkeygo/monotime v0.0.0-20180824235756-e3f48a95f98a/go.mod h1:ul4bvvnCOPZgq8w0nTkSmWVg/hauVpFS97Am1YM1XXo= 7 | gopkg.in/spacemonkeygo/monkit.v2 v2.0.0-20180827161543-6ebf5a752f9b h1:zkhw+LuPvld5/ZwIlpYzd4DX/r0KxTvhEpo+2lcrp9k= 8 | gopkg.in/spacemonkeygo/monkit.v2 v2.0.0-20180827161543-6ebf5a752f9b/go.mod h1:6UQdi0rNB4YDNwVYP8fJNmjLNaU8MA84WCdXStx3Spo= 9 | -------------------------------------------------------------------------------- /http.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package zipkin 16 | 17 | import ( 18 | "fmt" 19 | "net/http" 20 | 21 | "gopkg.in/spacemonkeygo/monkit.v2" 22 | ) 23 | 24 | var ( 25 | httpclient = monkit.ScopeNamed("http.client") 26 | httpserver = monkit.ScopeNamed("http.server") 27 | ) 28 | 29 | // Client is an interface that matches an http.Client 30 | type Client interface { 31 | Do(req *http.Request) (*http.Response, error) 32 | } 33 | 34 | func traceRequest(s *monkit.Span, cl Client, req *http.Request) ( 35 | resp *http.Response, err error) { 36 | s.Annotate("http.uri", req.URL.String()) 37 | RequestFromSpan(s).SetHeader(req.Header) 38 | resp, err = cl.Do(req) 39 | if err != nil { 40 | return resp, err 41 | } 42 | s.Annotate("http.responsecode", fmt.Sprint(resp.StatusCode)) 43 | return resp, nil 44 | } 45 | 46 | type responseWriterObserver struct { 47 | w http.ResponseWriter 48 | sc *int 49 | } 50 | 51 | func (w *responseWriterObserver) WriteHeader(status_code int) { 52 | w.sc = &status_code 53 | w.w.WriteHeader(status_code) 54 | } 55 | 56 | func (w *responseWriterObserver) Write(p []byte) (n int, err error) { 57 | if w.sc == nil { 58 | sc := 200 59 | w.sc = &sc 60 | } 61 | return w.w.Write(p) 62 | } 63 | 64 | func (w *responseWriterObserver) Header() http.Header { 65 | return w.w.Header() 66 | } 67 | 68 | func (w *responseWriterObserver) StatusCode() int { 69 | if w.sc == nil { 70 | return 200 71 | } 72 | return *w.sc 73 | } 74 | 75 | //go:generate sh -c "m4 -D_STDLIB_IMPORT_='\"context\"' -D_OTHER_IMPORT_= -D_BUILD_TAG_='// +build go1.7' httpctxgen.go.m4 > httpctx17.go" 76 | //go:generate sh -c "m4 -D_STDLIB_IMPORT_= -D_OTHER_IMPORT_='\"golang.org/x/net/context\"' -D_BUILD_TAG_='// +build !go1.7' httpctxgen.go.m4 > httpxctx.go" 77 | //go:generate gofmt -w -s httpctx17.go httpxctx.go 78 | -------------------------------------------------------------------------------- /httpctx17.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // WARNING: THE NON-M4 VERSIONS OF THIS FILE ARE GENERATED BY GO GENERATE! 16 | // ONLY MAKE CHANGES TO THE M4 FILE 17 | // 18 | 19 | // +build go1.7 20 | 21 | package zipkin 22 | 23 | import ( 24 | "context" 25 | "fmt" 26 | "net/http" 27 | 28 | "gopkg.in/spacemonkeygo/monkit.v2" 29 | ) 30 | 31 | // TraceRequest will perform an HTTP request, creating a new Span for the HTTP 32 | // request and sending the Span in the HTTP request headers. 33 | // Compare to http.Client.Do. 34 | func TraceRequest(ctx context.Context, cl Client, req *http.Request) ( 35 | resp *http.Response, err error) { 36 | defer httpclient.TaskNamed(req.Method)(&ctx)(&err) 37 | return traceRequest(monkit.SpanFromCtx(ctx), cl, req) 38 | } 39 | 40 | // TraceHandler wraps a ContextHTTPHandler with a Span pulled from incoming 41 | // requests, possibly starting new Traces if necessary. 42 | func TraceHandler(c ContextHTTPHandler) ContextHTTPHandler { 43 | return ContextHTTPHandlerFunc(func( 44 | ctx context.Context, w http.ResponseWriter, r *http.Request) { 45 | trace, spanId := RequestFromHeader(r.Header).Trace() 46 | defer httpserver.FuncNamed(r.Method).RemoteTrace(&ctx, spanId, trace)(nil) 47 | s := monkit.SpanFromCtx(ctx) 48 | s.Annotate("http.uri", r.RequestURI) 49 | wrapped := &responseWriterObserver{w: w} 50 | c.ServeHTTP(ctx, wrapped, r) 51 | s.Annotate("http.responsecode", fmt.Sprint(wrapped.StatusCode())) 52 | }) 53 | } 54 | 55 | // ContextHTTPHandler is like http.Handler, but expects a Context object 56 | // as the first parameter. 57 | type ContextHTTPHandler interface { 58 | ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request) 59 | } 60 | 61 | // ContextHTTPHandlerFunc is like http.HandlerFunc but for ContextHTTPHandlers 62 | type ContextHTTPHandlerFunc func( 63 | ctx context.Context, w http.ResponseWriter, r *http.Request) 64 | 65 | func (f ContextHTTPHandlerFunc) ServeHTTP(ctx context.Context, 66 | w http.ResponseWriter, r *http.Request) { 67 | f(ctx, w, r) 68 | } 69 | 70 | // ContextWrapper will turn a ContextHTTPHandler into an http.Handler by 71 | // passing a new Context into every request. 72 | func ContextWrapper(h ContextHTTPHandler) http.Handler { 73 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 74 | h.ServeHTTP(context.Background(), w, r) 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /httpctxgen.go.m4: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // WARNING: THE NON-M4 VERSIONS OF THIS FILE ARE GENERATED BY GO GENERATE! 16 | // ONLY MAKE CHANGES TO THE M4 FILE 17 | // 18 | 19 | _BUILD_TAG_ 20 | 21 | package zipkin 22 | 23 | import ( 24 | _STDLIB_IMPORT_ 25 | "fmt" 26 | "net/http" 27 | 28 | _OTHER_IMPORT_ 29 | "gopkg.in/spacemonkeygo/monkit.v2" 30 | ) 31 | 32 | // TraceRequest will perform an HTTP request, creating a new Span for the HTTP 33 | // request and sending the Span in the HTTP request headers. 34 | // Compare to http.Client.Do. 35 | func TraceRequest(ctx context.Context, cl Client, req *http.Request) ( 36 | resp *http.Response, err error) { 37 | defer httpclient.TaskNamed(req.Method)(&ctx)(&err) 38 | return traceRequest(monkit.SpanFromCtx(ctx), cl, req) 39 | } 40 | 41 | // TraceHandler wraps a ContextHTTPHandler with a Span pulled from incoming 42 | // requests, possibly starting new Traces if necessary. 43 | func TraceHandler(c ContextHTTPHandler) ContextHTTPHandler { 44 | return ContextHTTPHandlerFunc(func( 45 | ctx context.Context, w http.ResponseWriter, r *http.Request) { 46 | trace, spanId := RequestFromHeader(r.Header).Trace() 47 | defer httpserver.FuncNamed(r.Method).RemoteTrace(&ctx, spanId, trace)(nil) 48 | s := monkit.SpanFromCtx(ctx) 49 | s.Annotate("http.uri", r.RequestURI) 50 | wrapped := &responseWriterObserver{w: w} 51 | c.ServeHTTP(ctx, wrapped, r) 52 | s.Annotate("http.responsecode", fmt.Sprint(wrapped.StatusCode())) 53 | }) 54 | } 55 | 56 | // ContextHTTPHandler is like http.Handler, but expects a Context object 57 | // as the first parameter. 58 | type ContextHTTPHandler interface { 59 | ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request) 60 | } 61 | 62 | // ContextHTTPHandlerFunc is like http.HandlerFunc but for ContextHTTPHandlers 63 | type ContextHTTPHandlerFunc func( 64 | ctx context.Context, w http.ResponseWriter, r *http.Request) 65 | 66 | func (f ContextHTTPHandlerFunc) ServeHTTP(ctx context.Context, 67 | w http.ResponseWriter, r *http.Request) { 68 | f(ctx, w, r) 69 | } 70 | 71 | // ContextWrapper will turn a ContextHTTPHandler into an http.Handler by 72 | // passing a new Context into every request. 73 | func ContextWrapper(h ContextHTTPHandler) http.Handler { 74 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 75 | h.ServeHTTP(context.Background(), w, r) 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /httpxctx.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // WARNING: THE NON-M4 VERSIONS OF THIS FILE ARE GENERATED BY GO GENERATE! 16 | // ONLY MAKE CHANGES TO THE M4 FILE 17 | // 18 | 19 | // +build !go1.7 20 | 21 | package zipkin 22 | 23 | import ( 24 | "fmt" 25 | "net/http" 26 | 27 | "golang.org/x/net/context" 28 | "gopkg.in/spacemonkeygo/monkit.v2" 29 | ) 30 | 31 | // TraceRequest will perform an HTTP request, creating a new Span for the HTTP 32 | // request and sending the Span in the HTTP request headers. 33 | // Compare to http.Client.Do. 34 | func TraceRequest(ctx context.Context, cl Client, req *http.Request) ( 35 | resp *http.Response, err error) { 36 | defer httpclient.TaskNamed(req.Method)(&ctx)(&err) 37 | return traceRequest(monkit.SpanFromCtx(ctx), cl, req) 38 | } 39 | 40 | // TraceHandler wraps a ContextHTTPHandler with a Span pulled from incoming 41 | // requests, possibly starting new Traces if necessary. 42 | func TraceHandler(c ContextHTTPHandler) ContextHTTPHandler { 43 | return ContextHTTPHandlerFunc(func( 44 | ctx context.Context, w http.ResponseWriter, r *http.Request) { 45 | trace, spanId := RequestFromHeader(r.Header).Trace() 46 | defer httpserver.FuncNamed(r.Method).RemoteTrace(&ctx, spanId, trace)(nil) 47 | s := monkit.SpanFromCtx(ctx) 48 | s.Annotate("http.uri", r.RequestURI) 49 | wrapped := &responseWriterObserver{w: w} 50 | c.ServeHTTP(ctx, wrapped, r) 51 | s.Annotate("http.responsecode", fmt.Sprint(wrapped.StatusCode())) 52 | }) 53 | } 54 | 55 | // ContextHTTPHandler is like http.Handler, but expects a Context object 56 | // as the first parameter. 57 | type ContextHTTPHandler interface { 58 | ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request) 59 | } 60 | 61 | // ContextHTTPHandlerFunc is like http.HandlerFunc but for ContextHTTPHandlers 62 | type ContextHTTPHandlerFunc func( 63 | ctx context.Context, w http.ResponseWriter, r *http.Request) 64 | 65 | func (f ContextHTTPHandlerFunc) ServeHTTP(ctx context.Context, 66 | w http.ResponseWriter, r *http.Request) { 67 | f(ctx, w, r) 68 | } 69 | 70 | // ContextWrapper will turn a ContextHTTPHandler into an http.Handler by 71 | // passing a new Context into every request. 72 | func ContextWrapper(h ContextHTTPHandler) http.Handler { 73 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 74 | h.ServeHTTP(context.Background(), w, r) 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /rand.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package zipkin 16 | 17 | import ( 18 | crypto_rand "crypto/rand" 19 | "encoding/binary" 20 | "math/rand" 21 | "sync" 22 | ) 23 | 24 | type locker struct { 25 | l sync.Mutex 26 | s rand.Source 27 | } 28 | 29 | func (l *locker) Int63() (rv int64) { 30 | l.l.Lock() 31 | rv = l.s.Int63() 32 | l.l.Unlock() 33 | return rv 34 | } 35 | 36 | func (l *locker) Seed(seed int64) { 37 | l.l.Lock() 38 | l.s.Seed(seed) 39 | l.l.Unlock() 40 | } 41 | 42 | func seed() int64 { 43 | var seed [8]byte 44 | _, err := crypto_rand.Read(seed[:]) 45 | if err != nil { 46 | panic(err) 47 | } 48 | return int64(binary.BigEndian.Uint64(seed[:])) 49 | } 50 | 51 | var rng = rand.New(&locker{s: rand.NewSource(seed())}) 52 | -------------------------------------------------------------------------------- /register.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package zipkin 16 | 17 | import ( 18 | "fmt" 19 | "time" 20 | 21 | "github.com/spacemonkeygo/errors" 22 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2/gen-go/zipkin" 23 | monkit "gopkg.in/spacemonkeygo/monkit.v2" 24 | ) 25 | 26 | type traceKey int 27 | 28 | const ( 29 | sampleKey traceKey = 0 30 | flagsKey traceKey = 1 31 | remoteParentKey traceKey = 2 32 | ) 33 | 34 | type Options struct { 35 | Fraction float64 // The Fraction of traces to observe. 36 | Debug bool // Whether to set the debug flag on new traces. 37 | LocalHost *zipkin.Endpoint // What set as the local zipkin.Endpoint 38 | 39 | collector TraceCollector 40 | } 41 | 42 | // RegisterZipkin configures the given Registry reg to send the Spans from some 43 | // portion of all new Traces to the given TraceCollector. 44 | func RegisterZipkin(reg *monkit.Registry, collector TraceCollector, 45 | opts Options) { 46 | opts.collector = collector 47 | reg.ObserveTraces(func(t *monkit.Trace) { 48 | sampled, exists := t.Get(sampleKey).(bool) 49 | if !exists { 50 | sampled = rng.Float64() < opts.Fraction 51 | t.Set(sampleKey, sampled) 52 | } 53 | if sampled { 54 | flags, ok := t.Get(flagsKey).(int64) 55 | if !ok { 56 | flags = 0 57 | } 58 | if opts.Debug { 59 | flags = flags | 1 60 | } 61 | t.Set(flagsKey, flags) 62 | t.ObserveSpans(spanFinishObserverFunc(opts.observeSpan)) 63 | } 64 | }) 65 | } 66 | 67 | type spanFinishObserverFunc func(s *monkit.Span, err error, panicked bool, 68 | finish time.Time) 69 | 70 | func (f spanFinishObserverFunc) Start(*monkit.Span) {} 71 | func (f spanFinishObserverFunc) Finish(s *monkit.Span, err error, 72 | panicked bool, finish time.Time) { 73 | f(s, err, panicked, finish) 74 | } 75 | 76 | func getParentId(s *monkit.Span) (parent_id *int64, server bool) { 77 | parent := s.Parent() 78 | if parent != nil { 79 | parent_id := parent.Id() 80 | return &parent_id, false 81 | } 82 | if parent_id, ok := s.Trace().Get(remoteParentKey).(int64); ok { 83 | return &parent_id, true 84 | } 85 | return nil, false 86 | } 87 | 88 | func (opts Options) observeSpan(s *monkit.Span, err error, panicked bool, 89 | finish time.Time) { 90 | parent_id, server := getParentId(s) 91 | zs := &zipkin.Span{ 92 | TraceID: s.Trace().Id(), 93 | Name: s.Func().FullName(), 94 | ID: s.Id(), 95 | ParentID: parent_id, 96 | } 97 | 98 | start_name := zipkin.CLIENT_SEND 99 | end_name := zipkin.CLIENT_RECV 100 | if server { 101 | start_name = zipkin.SERVER_RECV 102 | end_name = zipkin.SERVER_SEND 103 | } 104 | 105 | annotations := s.Annotations() 106 | args := s.Args() 107 | 108 | zs.Annotations = make([]*zipkin.Annotation, 0, 4) 109 | zs.BinaryAnnotations = make([]*zipkin.BinaryAnnotation, 0, 110 | len(annotations)+len(args)+1) 111 | 112 | zs.Annotations = append(zs.Annotations, &zipkin.Annotation{ 113 | Timestamp: s.Start().UnixNano() / 1000, 114 | Value: start_name, 115 | Host: opts.LocalHost}) 116 | for arg_idx, arg := range args { 117 | zs.BinaryAnnotations = append(zs.BinaryAnnotations, 118 | &zipkin.BinaryAnnotation{ 119 | Key: fmt.Sprintf("arg_%d", arg_idx), 120 | Value: []byte(arg), 121 | AnnotationType: zipkin.AnnotationType_STRING, 122 | Host: opts.LocalHost}) 123 | } 124 | for _, annotation := range annotations { 125 | zs.BinaryAnnotations = append(zs.BinaryAnnotations, 126 | &zipkin.BinaryAnnotation{ 127 | Key: annotation.Name, 128 | Value: []byte(annotation.Value), 129 | AnnotationType: zipkin.AnnotationType_STRING, 130 | Host: opts.LocalHost}) 131 | } 132 | if panicked { 133 | zs.Annotations = append(zs.Annotations, &zipkin.Annotation{ 134 | Timestamp: finish.UnixNano() / 1000, 135 | Value: "failed", 136 | Host: opts.LocalHost}) 137 | zs.Annotations = append(zs.Annotations, &zipkin.Annotation{ 138 | Timestamp: finish.UnixNano() / 1000, 139 | Value: "panic", 140 | Host: opts.LocalHost}) 141 | } else if err != nil { 142 | zs.Annotations = append(zs.Annotations, &zipkin.Annotation{ 143 | Timestamp: finish.UnixNano() / 1000, 144 | Value: "failed", 145 | Host: opts.LocalHost}) 146 | zs.BinaryAnnotations = append(zs.BinaryAnnotations, 147 | &zipkin.BinaryAnnotation{ 148 | Key: "error", 149 | Value: []byte(errors.GetClass(err).String()), 150 | AnnotationType: zipkin.AnnotationType_STRING, 151 | Host: opts.LocalHost}) 152 | } 153 | zs.Annotations = append(zs.Annotations, &zipkin.Annotation{ 154 | Timestamp: finish.UnixNano() / 1000, 155 | Value: end_name, 156 | Host: opts.LocalHost}) 157 | opts.collector.Collect(zs) 158 | } 159 | -------------------------------------------------------------------------------- /request.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package zipkin 16 | 17 | import ( 18 | "strconv" 19 | 20 | "gopkg.in/spacemonkeygo/monkit.v2" 21 | ) 22 | 23 | // Request is a structure representing an incoming RPC request. Every field 24 | // is optional. 25 | type Request struct { 26 | TraceId *int64 27 | SpanId *int64 28 | ParentId *int64 29 | Sampled *bool 30 | Flags *int64 31 | } 32 | 33 | // HeaderGetter is an interface that http.Header matches for RequestFromHeader 34 | type HeaderGetter interface { 35 | Get(string) string 36 | } 37 | 38 | // HeaderSetter is an interface that http.Header matches for Request.SetHeader 39 | type HeaderSetter interface { 40 | Set(string, string) 41 | } 42 | 43 | // RequestFromHeader will create a Request object given an http.Header or 44 | // anything that matches the HeaderGetter interface. 45 | func RequestFromHeader(header HeaderGetter) (rv Request) { 46 | trace_id, err := fromHeader(header.Get("X-B3-TraceId")) 47 | if err == nil { 48 | rv.TraceId = &trace_id 49 | } 50 | span_id, err := fromHeader(header.Get("X-B3-SpanId")) 51 | if err == nil { 52 | rv.SpanId = &span_id 53 | } 54 | parent_id, err := fromHeader(header.Get("X-B3-ParentSpanId")) 55 | if err == nil { 56 | rv.ParentId = &parent_id 57 | } 58 | sampled, err := strconv.ParseBool(header.Get("X-B3-Sampled")) 59 | if err == nil { 60 | rv.Sampled = &sampled 61 | } 62 | flags, err := fromHeader(header.Get("X-B3-Flags")) 63 | if err == nil { 64 | rv.Flags = &flags 65 | } 66 | return rv 67 | } 68 | 69 | func ref(v int64) *int64 { 70 | return &v 71 | } 72 | 73 | func RequestFromSpan(s *monkit.Span) Request { 74 | trace := s.Trace() 75 | 76 | sampled, ok := trace.Get(sampleKey).(bool) 77 | if !ok { 78 | sampled = false 79 | } 80 | 81 | if !sampled { 82 | return Request{Sampled: &sampled} 83 | } 84 | flags, ok := trace.Get(flagsKey).(int64) 85 | if !ok { 86 | flags = 0 87 | } 88 | parent_id, _ := getParentId(s) 89 | return Request{ 90 | TraceId: ref(trace.Id()), 91 | SpanId: ref(s.Id()), 92 | Sampled: &sampled, 93 | Flags: &flags, 94 | ParentId: parent_id, 95 | } 96 | } 97 | 98 | // SetHeader will take a Request and fill out an http.Header, or anything that 99 | // matches the HeaderSetter interface. 100 | func (r Request) SetHeader(header HeaderSetter) { 101 | if r.TraceId != nil { 102 | header.Set("X-B3-TraceId", toHeader(*r.TraceId)) 103 | } 104 | if r.SpanId != nil { 105 | header.Set("X-B3-SpanId", toHeader(*r.SpanId)) 106 | } 107 | if r.ParentId != nil { 108 | header.Set("X-B3-ParentSpanId", toHeader(*r.ParentId)) 109 | } 110 | if r.Sampled != nil { 111 | header.Set("X-B3-Sampled", strconv.FormatBool(*r.Sampled)) 112 | } 113 | if r.Flags != nil { 114 | header.Set("X-B3-Flags", toHeader(*r.Flags)) 115 | } 116 | } 117 | 118 | func (zipreq Request) Trace() (trace *monkit.Trace, spanId int64) { 119 | if zipreq.TraceId != nil { 120 | trace = monkit.NewTrace(*zipreq.TraceId) 121 | } else { 122 | trace = monkit.NewTrace(monkit.NewId()) 123 | } 124 | if zipreq.SpanId != nil { 125 | spanId = *zipreq.SpanId 126 | } else { 127 | spanId = monkit.NewId() 128 | } 129 | 130 | if zipreq.ParentId != nil { 131 | trace.Set(remoteParentKey, *zipreq.ParentId) 132 | } 133 | if zipreq.Sampled != nil { 134 | trace.Set(sampleKey, *zipreq.Sampled) 135 | } 136 | if zipreq.Flags != nil { 137 | trace.Set(flagsKey, *zipreq.Flags) 138 | } 139 | return trace, spanId 140 | } 141 | 142 | // fromHeader reads a signed int64 that has been formatted as a hex uint64 143 | func fromHeader(s string) (int64, error) { 144 | v, err := strconv.ParseUint(s, 16, 64) 145 | return int64(v), err 146 | } 147 | 148 | // toHeader writes a signed int64 as hex uint64 149 | func toHeader(i int64) string { 150 | return strconv.FormatUint(uint64(i), 16) 151 | } 152 | -------------------------------------------------------------------------------- /scribe.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package zipkin 16 | 17 | import ( 18 | "context" 19 | "encoding/base64" 20 | "errors" 21 | "log" 22 | "net" 23 | "time" 24 | 25 | "github.com/apache/thrift/lib/go/thrift" 26 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2/gen-go/scribe" 27 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2/gen-go/zipkin" 28 | ) 29 | 30 | // ScribeCollector matches the TraceCollector interface, but writes directly 31 | // to a connected Scribe socket. 32 | type ScribeCollector struct { 33 | addr *net.TCPAddr 34 | done chan struct{} 35 | 36 | logs chan *scribe.LogEntry 37 | } 38 | 39 | // NewScribeCollector creates a ScribeCollector. scribe_addr is the address 40 | // of the Scribe endpoint, typically "127.0.0.1:9410" 41 | func NewScribeCollector(scribe_addr string) (*ScribeCollector, error) { 42 | sa, err := net.ResolveTCPAddr("tcp", scribe_addr) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | s := ScribeCollector{ 48 | addr: sa, 49 | done: make(chan struct{}), 50 | logs: make(chan *scribe.LogEntry, 100), 51 | } 52 | 53 | go s.pumpWrites(context.Background()) 54 | 55 | return &s, nil 56 | } 57 | 58 | // pumpWrites sends all messages on s.logs to scribe. It creates the 59 | // scribe connections, recreates them when write errors occur, and 60 | // backs off on consecutive connection errors. 61 | // 62 | // When a write error occurs, pumpWrites will lose that log entry. 63 | func (s *ScribeCollector) pumpWrites(ctx context.Context) { 64 | var backoff int 65 | 66 | for { 67 | select { 68 | case <-s.done: 69 | return 70 | case <-time.After(defaultBackoff.duration(backoff)): 71 | } 72 | 73 | conn, err := newScribeConn(s.addr) 74 | if err != nil { 75 | log.Printf("connect error: %s", err) 76 | backoff++ 77 | continue 78 | } 79 | 80 | err = writeAll(ctx, conn, s.logs, s.done) 81 | if err != nil { 82 | log.Printf("write error: %s", err) 83 | } 84 | 85 | backoff = 0 86 | } 87 | } 88 | 89 | // writeAll sends all logs to c, stopping when done is signaled. 90 | func writeAll(ctx context.Context, c *scribeConn, logs <-chan *scribe.LogEntry, 91 | done <-chan struct{}) error { 92 | for { 93 | select { 94 | case l := <-logs: 95 | rc, err := c.client.Log(ctx, []*scribe.LogEntry{l}) 96 | if err != nil { 97 | return err 98 | } 99 | 100 | // Non-OK responses are logged but not fatal 101 | // for the connection. 102 | if rc != scribe.ResultCode_OK { 103 | log.Printf("scribe result code not OK: %s", rc) 104 | } 105 | case <-done: 106 | return nil 107 | } 108 | } 109 | } 110 | 111 | // Close closes an existing ScribeCollector 112 | func (s *ScribeCollector) Close() error { 113 | close(s.done) 114 | return nil 115 | } 116 | 117 | // CollectSerialized buffers a serialized zipkin.Span to be sent to 118 | // the Scribe endpoint. It returns an error and loses the log entry if 119 | // the buffer is full. 120 | func (c *ScribeCollector) CollectSerialized(serialized []byte) error { 121 | entry := scribe.LogEntry{ 122 | Category: "zipkin", 123 | Message: base64.StdEncoding.EncodeToString(serialized), 124 | } 125 | 126 | select { 127 | case c.logs <- &entry: 128 | return nil 129 | default: 130 | return errors.New("skipping scribe log: buffer full") 131 | } 132 | } 133 | 134 | // Collect will serialize and send a zipkin.Span to the configured Scribe 135 | // endpoint 136 | func (c *ScribeCollector) Collect(s *zipkin.Span) { 137 | t := thrift.NewTMemoryBuffer() 138 | p := thrift.NewTBinaryProtocolTransport(t) 139 | err := s.Write(p) 140 | if err != nil { 141 | log.Printf("failed write: %v", err) 142 | return 143 | } 144 | err = c.CollectSerialized(t.Buffer.Bytes()) 145 | if err != nil { 146 | log.Printf("failed collect: %v", err) 147 | } 148 | } 149 | 150 | type scribeConn struct { 151 | transport *thrift.TFramedTransport 152 | client *scribe.ScribeClient 153 | } 154 | 155 | func newScribeConn(addr *net.TCPAddr) (*scribeConn, error) { 156 | transport := thrift.NewTFramedTransport( 157 | thrift.NewTSocketFromAddrTimeout(addr, 10*time.Second)) 158 | err := transport.Open() 159 | if err != nil { 160 | return nil, err 161 | } 162 | 163 | proto := thrift.NewTBinaryProtocolTransport(transport) 164 | conn := scribeConn{ 165 | transport: transport, 166 | client: scribe.NewScribeClientProtocol(transport, proto, proto), 167 | } 168 | 169 | return &conn, nil 170 | } 171 | 172 | func (c *scribeConn) Close() { 173 | c.transport.Close() 174 | } 175 | 176 | var _ TraceCollector = (*ScribeCollector)(nil) 177 | -------------------------------------------------------------------------------- /scribe.thrift: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Twitter Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | namespace java com.twitter.zipkin.gen 15 | 16 | enum ResultCode 17 | { 18 | OK, 19 | TRY_LATER 20 | } 21 | 22 | struct LogEntry 23 | { 24 | 1: string category, 25 | 2: string message 26 | } 27 | 28 | service Scribe 29 | { 30 | ResultCode Log(1: list messages); 31 | } 32 | -------------------------------------------------------------------------------- /udp.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Space Monkey, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package zipkin 16 | 17 | import ( 18 | "log" 19 | "net" 20 | 21 | "github.com/apache/thrift/lib/go/thrift" 22 | "gopkg.in/spacemonkeygo/monkit-zipkin.v2/gen-go/zipkin" 23 | ) 24 | 25 | const ( 26 | maxPacketSize = 8192 27 | ) 28 | 29 | // UDPCollector matches the TraceCollector interface, but sends serialized 30 | // zipkin.Span objects over UDP, instead of the Scribe protocol. See 31 | // RedirectPackets for the UDP server-side code. 32 | type UDPCollector struct { 33 | ch chan *zipkin.Span 34 | conn *net.UDPConn 35 | addr *net.UDPAddr 36 | } 37 | 38 | // NewUDPCollector creates a UDPCollector that sends packets to collector_addr. 39 | // buffer_size is how many outstanding unsent zipkin.Span objects can exist 40 | // before Spans start getting dropped. 41 | func NewUDPCollector(collector_addr string, buffer_size int) ( 42 | *UDPCollector, error) { 43 | addr, err := net.ResolveUDPAddr("udp", collector_addr) 44 | if err != nil { 45 | return nil, err 46 | } 47 | conn, err := net.ListenUDP("udp", nil) 48 | if err != nil { 49 | return nil, err 50 | } 51 | c := &UDPCollector{ 52 | ch: make(chan *zipkin.Span, buffer_size), 53 | conn: conn, 54 | addr: addr} 55 | go c.handle() 56 | return c, nil 57 | } 58 | 59 | func (c *UDPCollector) handle() { 60 | for { 61 | select { 62 | case s, ok := <-c.ch: 63 | if !ok { 64 | return 65 | } 66 | err := c.send(s) 67 | if err != nil { 68 | log.Printf("failed write: %v", err) 69 | } 70 | } 71 | } 72 | } 73 | 74 | func (c *UDPCollector) send(s *zipkin.Span) error { 75 | t := thrift.NewTMemoryBuffer() 76 | p := thrift.NewTBinaryProtocolTransport(t) 77 | err := s.Write(p) 78 | if err != nil { 79 | return err 80 | } 81 | _, err = c.conn.WriteToUDP(t.Buffer.Bytes(), c.addr) 82 | return err 83 | } 84 | 85 | // Collect takes a zipkin.Span object, serializes it, and sends it to the 86 | // configured collector_addr. 87 | func (c *UDPCollector) Collect(span *zipkin.Span) { 88 | select { 89 | case c.ch <- span: 90 | default: 91 | } 92 | } 93 | 94 | // RedirectPackets is a method that handles incoming packets from the 95 | // UDPCollector class. RedirectPackets, when running, will listen for UDP 96 | // packets containing serialized zipkin.Span objects on listen_addr, then will 97 | // resend those packets to the given ScribeCollector. On any error, 98 | // RedirectPackets currently aborts. 99 | func RedirectPackets(listen_addr string, collector *ScribeCollector) error { 100 | la, err := net.ResolveUDPAddr("udp", listen_addr) 101 | if err != nil { 102 | return err 103 | } 104 | conn, err := net.ListenUDP("udp", la) 105 | if err != nil { 106 | return err 107 | } 108 | defer conn.Close() 109 | var buf [maxPacketSize]byte 110 | for { 111 | n, _, err := conn.ReadFrom(buf[:]) 112 | if err != nil { 113 | return err 114 | } 115 | err = collector.CollectSerialized(buf[:n]) 116 | if err != nil { 117 | return err 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /zipkin.thrift: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Twitter Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | namespace java com.twitter.zipkin.gen 15 | namespace rb Zipkin 16 | 17 | //************** Collection related structs ************** 18 | 19 | // these are the annotations we always expect to find in a span 20 | const string CLIENT_SEND = "cs" 21 | const string CLIENT_RECV = "cr" 22 | const string SERVER_SEND = "ss" 23 | const string SERVER_RECV = "sr" 24 | 25 | // this represents a host and port in a network 26 | struct Endpoint { 27 | 1: i32 ipv4, 28 | 2: i16 port // beware that this will give us negative ports. some conversion needed 29 | 3: string service_name // which service did this operation happen on? 30 | } 31 | 32 | // some event took place, either one by the framework or by the user 33 | struct Annotation { 34 | 1: i64 timestamp // microseconds from epoch 35 | 2: string value // what happened at the timestamp? 36 | 3: optional Endpoint host // host this happened on 37 | 4: optional i32 duration // how long did the operation take? microseconds 38 | } 39 | 40 | enum AnnotationType { BOOL, BYTES, I16, I32, I64, DOUBLE, STRING } 41 | 42 | struct BinaryAnnotation { 43 | 1: string key, 44 | 2: binary value, 45 | 3: AnnotationType annotation_type, 46 | 4: optional Endpoint host 47 | } 48 | 49 | struct Span { 50 | 1: i64 trace_id // unique trace id, use for all spans in trace 51 | 3: string name, // span name, rpc method for example 52 | 4: i64 id, // unique span id, only used for this span 53 | 5: optional i64 parent_id, // parent span id 54 | 6: list annotations, // list of all annotations/events that occured 55 | 8: list binary_annotations // any binary annotations 56 | 9: optional bool debug = 0 // if true, we DEMAND that this span passes all samplers 57 | } 58 | 59 | --------------------------------------------------------------------------------