github.com/uber-go/tally/v4@v4.1.17/m3/example/local_server.go (about) 1 // Copyright (c) 2021 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package main 22 23 import ( 24 "bytes" 25 "fmt" 26 "net" 27 "sync/atomic" 28 29 "github.com/uber-go/tally/v4/m3" 30 customtransport "github.com/uber-go/tally/v4/m3/customtransports" 31 m3thrift "github.com/uber-go/tally/v4/m3/thrift/v1" 32 "github.com/uber-go/tally/v4/thirdparty/github.com/apache/thrift/lib/go/thrift" 33 ) 34 35 type batchCallback func(batch *m3thrift.MetricBatch) 36 37 type localM3Server struct { 38 Service *localM3Service 39 Addr string 40 protocol m3.Protocol 41 processor thrift.TProcessor 42 conn *net.UDPConn 43 closed int32 44 } 45 46 func newLocalM3Server( 47 listenAddr string, 48 protocol m3.Protocol, 49 fn batchCallback, 50 ) (*localM3Server, error) { 51 udpAddr, err := net.ResolveUDPAddr("udp", listenAddr) 52 if err != nil { 53 return nil, err 54 } 55 56 service := newLocalM3Service(fn) 57 processor := m3thrift.NewM3Processor(service) 58 conn, err := net.ListenUDP(udpAddr.Network(), udpAddr) 59 if err != nil { 60 return nil, err 61 } 62 63 return &localM3Server{ 64 Service: service, 65 Addr: conn.LocalAddr().String(), 66 conn: conn, 67 protocol: protocol, 68 processor: processor, 69 }, nil 70 } 71 72 func (f *localM3Server) Serve() error { 73 readBuf := make([]byte, 65536) 74 for { 75 n, err := f.conn.Read(readBuf) 76 if err != nil { 77 if atomic.LoadInt32(&f.closed) == 0 { 78 return fmt.Errorf("failed to read: %v", err) 79 } 80 return nil 81 } 82 trans, _ := customtransport.NewTBufferedReadTransport(bytes.NewBuffer(readBuf[0:n])) 83 var proto thrift.TProtocol 84 if f.protocol == m3.Compact { 85 proto = thrift.NewTCompactProtocol(trans) 86 } else { 87 proto = thrift.NewTBinaryProtocolTransport(trans) 88 } 89 90 if _, err = f.processor.Process(proto, proto); err != nil { 91 fmt.Println("Error processing thrift metric:", err) 92 } 93 } 94 } 95 96 func (f *localM3Server) Close() error { 97 atomic.AddInt32(&f.closed, 1) 98 return f.conn.Close() 99 } 100 101 type localM3Service struct { 102 fn batchCallback 103 } 104 105 func newLocalM3Service(fn batchCallback) *localM3Service { 106 return &localM3Service{fn: fn} 107 } 108 109 func (m *localM3Service) EmitMetricBatch(batch *m3thrift.MetricBatch) (err error) { 110 m.fn(batch) 111 return thrift.NewTTransportException(thrift.END_OF_FILE, "complete") 112 }