1919// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020// THE SOFTWARE.
2121
22+ var fs = require ( 'fs' ) ;
23+ var path = require ( 'path' ) ;
24+
2225var program = require ( 'commander' ) ;
2326var RingPop = require ( './index' ) ;
2427var TChannel = require ( 'tchannel' ) ;
@@ -28,7 +31,7 @@ function main(args) {
2831 . version ( require ( './package.json' ) . version )
2932
3033 . usage ( '[options]' )
31-
34+
3235 . option ( '-l, --listen <listen>' ,
3336 'Host and port on which server listens (also node\'s identity in cluster)' )
3437
@@ -47,6 +50,15 @@ function main(args) {
4750 'The lifetime of a tombstone member in ms. After that the member is removed from the membership.' ,
4851 parseInt10 , 5000 )
4952
53+ . option ( '--stats-file <stats-file>' ,
54+ 'Enable stats emitting to a file. Stats-file can be a relative or absolute path. ' +
55+ 'Note: this flag is mutually exclusive with --stats-udp and you need to manually install "uber-statsd-client" to be able to emit stats' )
56+
57+ . option ( '--stats-udp <stats-udp>' ,
58+ 'Enable stats emitting over udp. Destination is in the host-port format (e.g. localhost:8125 or 127.0.0.1:8125) ' +
59+ 'Note: this flag is mutually exclusive with --stats-file and you need to manually install "uber-statsd-client" to be able to emit stats' ,
60+ / ^ ( .+ ) : ( \d + ) $ / )
61+
5062 . parse ( args ) ;
5163
5264 var listen = program . listen ;
@@ -56,6 +68,8 @@ function main(args) {
5668 process . exit ( 1 ) ;
5769 }
5870
71+ var stats = createStatsClient ( program ) ;
72+
5973 var tchannel = new TChannel ( {
6074 } ) ;
6175
@@ -72,7 +86,8 @@ function main(args) {
7286 suspect : program . suspectPeriod ,
7387 faulty : program . faultyPeriod ,
7488 tombstone : program . tombstonePeriod ,
75- }
89+ } ,
90+ statsd : stats
7691 } ) ;
7792
7893 ringpop . setupChannel ( ) ;
@@ -87,6 +102,82 @@ function main(args) {
87102 }
88103}
89104
105+ function createStatsClient ( program ) {
106+ if ( ! program . statsUdp && ! program . statsFile ) {
107+ return null ;
108+ }
109+ if ( program . statsUdp && program . statsFile ) {
110+ console . error ( "--stats-udp and --stats-file are mutually exclusive." ) ;
111+ console . error ( "Please specify only one of the two options!" ) ;
112+ process . exit ( 1 ) ;
113+ }
114+
115+ var opts = null ;
116+ if ( program . statsUdp ) {
117+ var matchesHostPort = program . statsUdp . match ( / ^ ( .+ ) : ( \d + ) $ / ) ;
118+ opts = {
119+ host : matchesHostPort [ 1 ] ,
120+ port : parseInt ( matchesHostPort [ 2 ] )
121+ } ;
122+ } else if ( program . statsFile ) {
123+ var file = path . resolve ( program . statsFile ) ;
124+ opts = {
125+ // passing in our own 'socket' implementation here so we can write to file instead.
126+ // note: this is non-public api and could change without warning.
127+ _ephemeralSocket : new FileStatsLogger ( file )
128+ } ;
129+ }
130+
131+ var createStatsdClient ;
132+
133+ // Wrap the require in a try/catch so we're don't have to add uber-statsd-client
134+ // as a dependency but fail gracefully when not available.
135+ try {
136+ createStatsdClient = require ( 'uber-statsd-client' ) ;
137+ } catch ( e ) {
138+ if ( e . code !== "MODULE_NOT_FOUND" ) {
139+ throw e ;
140+ }
141+
142+ console . error ( "To be able to emit stats you need to have uber-statsd-client installed." ) ;
143+ console . error ( "Please run \"npm install uber-statsd-client\" and try again!" ) ;
144+ process . exit ( 1 ) ;
145+ }
146+
147+ return createStatsdClient ( opts ) ;
148+ }
149+
150+ function FileStatsLogger ( file ) {
151+ if ( ! ( this instanceof FileStatsLogger ) ) {
152+ return new FileStatsLogger ( file ) ;
153+ }
154+
155+ this . file = file ;
156+ this . stream = null ;
157+ this . ensureStream ( ) ;
158+ }
159+
160+ FileStatsLogger . prototype . ensureStream = function ensureStream ( ) {
161+ if ( this . stream ) {
162+ return ;
163+ }
164+ this . stream = fs . createWriteStream ( this . file , { flags : 'a' } ) ;
165+ } ;
166+
167+ FileStatsLogger . prototype . close = function close ( ) {
168+ if ( this . stream ) {
169+ this . stream . end ( ) ;
170+ this . stream = null ;
171+ }
172+ } ;
173+
174+ FileStatsLogger . prototype . _writeToSocket = function _writeToSocket ( data , cb ) {
175+ this . ensureStream ( ) ;
176+ this . stream . write ( new Date ( ) . toISOString ( ) + ': ' + data + '\n' , cb ) ;
177+ } ;
178+
179+ FileStatsLogger . prototype . send = FileStatsLogger . prototype . _writeToSocket ;
180+
90181function parseInt10 ( str ) {
91182 return parseInt ( str , 10 ) ;
92183}
0 commit comments