tsd_metrics 0.2.0 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ # Copyright 2014 Groupon.com
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
+ module TsdMetrics
16
+ UNITS = Set.new([:nanosecond, :microsecond, :millisecond, :second, :minute, :hour, :day, :week, :bit, :byte, :kilobit, :kilobyte, :megabit, :megabyte, :gigabit, :gigabyte, :terabyte, :petabyte])
17
+ class UnitsUtils
18
+ def self.isValidUnitValue?(unit)
19
+ return unit == :noUnit || UNITS.include?(unit)
20
+ end
21
+ end
22
+ end
data/lib/tsd_metrics.rb CHANGED
@@ -1,32 +1,80 @@
1
- require_relative 'tsd_metrics/tsd_metric_2c'
1
+ # Copyright 2014 Groupon.com
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
+ require_relative 'tsd_metrics/tsd_metric'
2
16
  require_relative 'tsd_metrics/queue_writer'
3
17
  require_relative 'tsd_metrics/async_queue_writer'
4
18
  require_relative 'tsd_metrics/metric_builder_for_single_struct_receiver'
5
- require_relative 'tsd_metrics/json_formatter_receiver'
19
+ require_relative 'tsd_metrics/json_formatting_sink'
6
20
  require 'thread'
7
21
  require 'logger'
8
22
 
9
23
  module TsdMetrics
24
+ attr_reader :errorLogger
10
25
  @metricBuilder = nil
11
- @writerThread = nil
12
- @fileWriter = nil
26
+ @@errorLogger = nil
13
27
 
14
- def self.buildMetric
15
- init() if @metricBuilder == nil
16
- @metricBuilder.build
17
- end
28
+ # +filename+:: Optional: the relative or absolute path to output metrics. Default: 'query.log' in the working directory
29
+ # +errorLogger+:: Optional: a place to which mis-uses of the library can be logged.
30
+ # Expects methods +info+, +warn+, +error+
31
+ # +rollLogs+:: Optional: Have the library do log rolling; not thread-safe! Setting to false means the library-user should have external log-rolling in place. Default: true
32
+ def self.init(providedOpts={})
33
+ defaultOpts = {filename: "query.log", rollLogs: true}
34
+ opts = defaultOpts.merge providedOpts
35
+ @errorLogger = opts[:errorLogger] || Logger.new(STDOUT)
18
36
 
19
- def self.init(filename="tsd_metric_2c.json")
20
37
  outputFileQueue = Queue.new
21
- # create writer
38
+
39
+ # JSON to queue
22
40
  writer = QueueWriter.new(outputFileQueue)
23
- # create json formatter to take newly-closed metrics
24
- formatterStructReveiver = JsonFormatterReceiver.new(writer)
41
+
42
+ # Metric to JSON
43
+ formatterStructReveiver = JsonFormattingSink.new(writer)
25
44
  @metricBuilder = MetricBuilderForSingleStructReceiver.new(formatterStructReveiver)
26
- logger = createHeaderlessLogger(filename, "daily")
27
- # Create async monitor
28
- @queueToFileWriter = AsyncQueueWriter.new(outputFileQueue, logger)
45
+
46
+ loggerOptions = [opts[:filename]]
47
+ # Set the ':daily' option on the logger if we want to roll the logs
48
+ loggerOptions.push(:daily) if opts[:rollLogs]
49
+ # TODO(mhayter): Switch to hourly rolling (will need different log lib)
50
+ # [MAI-173]
51
+ # File writer
52
+ toFileLogger = createHeaderlessLogger(*loggerOptions)
53
+
54
+ # Queue to file
55
+ @queueToFileWriter = AsyncQueueWriter.new(outputFileQueue, toFileLogger)
29
56
  @queueToFileWriter.start
57
+
58
+ # Phusion Passenger loses all threads on a fork, this is added
59
+ # so that the writing thread is recreated.
60
+ # This code was found at
61
+ # https://www.phusionpassenger.com/documentation/Users%20guide%20Nginx.html#_smart_spawning_caveat_2_the_need_to_revive_threads
62
+ if defined?(PhusionPassenger)
63
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
64
+ if forked
65
+ outputFileQueue.clear
66
+ @queueToFileWriter.start
67
+ else
68
+ # We're in direct spawning mode. We don't need to do anything.
69
+ end
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ def self.buildMetric
76
+ init() if @metricBuilder == nil
77
+ @metricBuilder.build
30
78
  end
31
79
 
32
80
  private
data/resources/LICENSE ADDED
@@ -0,0 +1,158 @@
1
+ Apache License
2
+
3
+ Version 2.0, January 2004
4
+
5
+ http://www.apache.org/licenses/
6
+
7
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
+
9
+ 1. Definitions.
10
+
11
+ "License" shall mean the terms and conditions for use, reproduction, and
12
+ distribution as defined by Sections 1 through 9 of this document.
13
+
14
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright
15
+ owner that is granting the License.
16
+
17
+ "Legal Entity" shall mean the union of the acting entity and all other entities
18
+ that control, are controlled by, or are under common control with that entity.
19
+ For the purposes of this definition, "control" means (i) the power, direct or
20
+ indirect, to cause the direction or management of such entity, whether by
21
+ contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity exercising
25
+ permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications, including
28
+ but not limited to software source code, documentation source, and configuration
29
+ files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical transformation or
32
+ translation of a Source form, including but not limited to compiled object code,
33
+ generated documentation, and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or Object form, made
36
+ available under the License, as indicated by a copyright notice that is included
37
+ in or attached to the work (an example is provided in the Appendix below).
38
+
39
+ "Derivative Works" shall mean any work, whether in Source or Object form, that
40
+ is based on (or derived from) the Work and for which the editorial revisions,
41
+ annotations, elaborations, or other modifications represent, as a whole, an
42
+ original work of authorship. For the purposes of this License, Derivative Works
43
+ shall not include works that remain separable from, or merely link (or bind by
44
+ name) to the interfaces of, the Work and Derivative Works thereof.
45
+
46
+ "Contribution" shall mean any work of authorship, including the original version
47
+ of the Work and any modifications or additions to that Work or Derivative Works
48
+ thereof, that is intentionally submitted to Licensor for inclusion in the Work
49
+ by the copyright owner or by an individual or Legal Entity authorized to submit
50
+ on behalf of the copyright owner. For the purposes of this definition,
51
+ "submitted" means any form of electronic, verbal, or written communication sent
52
+ to the Licensor or its representatives, including but not limited to
53
+ communication on electronic mailing lists, source code control systems, and
54
+ issue tracking systems that are managed by, or on behalf of, the Licensor for
55
+ the purpose of discussing and improving the Work, but excluding communication
56
+ that is conspicuously marked or otherwise designated in writing by the copyright
57
+ owner as "Not a Contribution."
58
+
59
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
60
+ of whom a Contribution has been received by Licensor and subsequently
61
+ incorporated within the Work.
62
+
63
+ 2. Grant of Copyright License. Subject to the terms and conditions of this
64
+ License, each Contributor hereby grants to You a perpetual, worldwide,
65
+ non-exclusive, no-charge, royalty-free, irrevocable copyright license to
66
+ reproduce, prepare Derivative Works of, publicly display, publicly perform,
67
+ sublicense, and distribute the Work and such Derivative Works in Source or
68
+ Object form.
69
+
70
+ 3. Grant of Patent License. Subject to the terms and conditions of this License,
71
+ each Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
72
+ no-charge, royalty-free, irrevocable (except as stated in this section) patent
73
+ license to make, have made, use, offer to sell, sell, import, and otherwise
74
+ transfer the Work, where such license applies only to those patent claims
75
+ licensable by such Contributor that are necessarily infringed by their
76
+ Contribution(s) alone or by combination of their Contribution(s) with the Work
77
+ to which such Contribution(s) was submitted. If You institute patent litigation
78
+ against any entity (including a cross-claim or counterclaim in a lawsuit)
79
+ alleging that the Work or a Contribution incorporated within the Work
80
+ constitutes direct or contributory patent infringement, then any patent licenses
81
+ granted to You under this License for that Work shall terminate as of the date
82
+ such litigation is filed.
83
+
84
+ 4. Redistribution. You may reproduce and distribute copies of the Work or
85
+ Derivative Works thereof in any medium, with or without modifications, and in
86
+ Source or Object form, provided that You meet the following conditions:
87
+
88
+ a. You must give any other recipients of the Work or Derivative Works a copy of
89
+ this License; and
90
+ b. You must cause any modified files to carry prominent notices stating that You
91
+ changed the files; and
92
+ c. You must retain, in the Source form of any Derivative Works that You
93
+ distribute, all copyright, patent, trademark, and attribution notices from the
94
+ Source form of the Work, excluding those notices that do not pertain to any part
95
+ of the Derivative Works; and
96
+ d. If the Work includes a "NOTICE" text file as part of its distribution, then
97
+ any Derivative Works that You distribute must include a readable copy of the
98
+ attribution notices contained within such NOTICE file, excluding those notices
99
+ that do not pertain to any part of the Derivative Works, in at least one of the
100
+ following places: within a NOTICE text file distributed as part of the
101
+ Derivative Works; within the Source form or documentation, if provided along
102
+ with the Derivative Works; or, within a display generated by the Derivative
103
+ Works, if and wherever such third-party notices normally appear. The contents of
104
+ the NOTICE file are for informational purposes only and do not modify the
105
+ License. You may add Your own attribution notices within Derivative Works that
106
+ You distribute, alongside or as an addendum to the NOTICE text from the Work,
107
+ provided that such additional attribution notices cannot be construed as
108
+ modifying the License.
109
+
110
+ You may add Your own copyright statement to Your modifications and may provide
111
+ additional or different license terms and conditions for use, reproduction, or
112
+ distribution of Your modifications, or for any such Derivative Works as a whole,
113
+ provided Your use, reproduction, and distribution of the Work otherwise complies
114
+ with the conditions stated in this License.
115
+
116
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any
117
+ Contribution intentionally submitted for inclusion in the Work by You to the
118
+ Licensor shall be under the terms and conditions of this License, without any
119
+ additional terms or conditions. Notwithstanding the above, nothing herein shall
120
+ supersede or modify the terms of any separate license agreement you may have
121
+ executed with Licensor regarding such Contributions.
122
+
123
+ 6. Trademarks. This License does not grant permission to use the trade names,
124
+ trademarks, service marks, or product names of the Licensor, except as required
125
+ for reasonable and customary use in describing the origin of the Work and
126
+ reproducing the content of the NOTICE file.
127
+
128
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in
129
+ writing, Licensor provides the Work (and each Contributor provides its
130
+ Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
131
+ KIND, either express or implied, including, without limitation, any warranties
132
+ or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
133
+ PARTICULAR PURPOSE. You are solely responsible for determining the
134
+ appropriateness of using or redistributing the Work and assume any risks
135
+ associated with Your exercise of permissions under this License.
136
+
137
+ 8. Limitation of Liability. In no event and under no legal theory, whether in
138
+ tort (including negligence), contract, or otherwise, unless required by
139
+ applicable law (such as deliberate and grossly negligent acts) or agreed to in
140
+ writing, shall any Contributor be liable to You for damages, including any
141
+ direct, indirect, special, incidental, or consequential damages of any character
142
+ arising as a result of this License or out of the use or inability to use the
143
+ Work (including but not limited to damages for loss of goodwill, work stoppage,
144
+ computer failure or malfunction, or any and all other commercial damages or
145
+ losses), even if such Contributor has been advised of the possibility of such
146
+ damages.
147
+
148
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or
149
+ Derivative Works thereof, You may choose to offer, and charge a fee for,
150
+ acceptance of support, warranty, indemnity, or other liability obligations
151
+ and/or rights consistent with this License. However, in accepting such
152
+ obligations, You may act only on Your own behalf and on Your sole
153
+ responsibility, not on behalf of any other Contributor, and only if You agree
154
+ to indemnify, defend, and hold each Contributor harmless for any liability
155
+ incurred by, or claims asserted against, such Contributor by reason of your
156
+ accepting any such warranty or additional liability.
157
+
158
+ END OF TERMS AND CONDITIONS
@@ -0,0 +1,84 @@
1
+ # Copyright 2014 Groupon.com
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
+ require "tsd_metrics"
16
+ require "thread"
17
+ require "pry"
18
+ require "json-schema"
19
+
20
+ describe "creating metrics" do
21
+ before(:each) do
22
+ begin
23
+ File.delete filename
24
+ rescue
25
+ end
26
+ end
27
+ let(:filename) { "my_file.json" }
28
+
29
+ def checkFileForNWellFormedLines(n)
30
+ File.open filename, "r" do |file|
31
+ count = 0
32
+ while true
33
+ line = file.readline rescue break
34
+ JSON::Validator.validate!("doc/query-log-schema-2e.json", line)
35
+ count += 1
36
+ end
37
+ count.should == n
38
+ end
39
+ end
40
+
41
+ it "writes three metrics to the file" do
42
+ # init
43
+ TsdMetrics.init(filename: filename)
44
+ # build metric, close
45
+ metric = TsdMetrics.buildMetric
46
+ metric.startTimer("myTimer")
47
+ metric.setGauge("myGauge", 20)
48
+ metric.incrementCounter("myCounter", 20)
49
+ metric.stopTimer("myTimer")
50
+ metric.close
51
+ # metric, close
52
+ metric = TsdMetrics.buildMetric
53
+ metric.setGauge("myGauge", 20)
54
+ metric.close
55
+ # metric, close
56
+ metric = TsdMetrics.buildMetric
57
+ metric.setGauge("myGauge", 20)
58
+ metric.close
59
+
60
+ sleep(0.1)
61
+
62
+ checkFileForNWellFormedLines(3)
63
+ end
64
+
65
+ it "does not write empty metrics to the file" do
66
+ TsdMetrics.init(filename: filename)
67
+ # build metric, close
68
+ metric = TsdMetrics.buildMetric
69
+ metric.setGauge("myGauge", 20)
70
+ metric.close
71
+ # metric, close
72
+ metric = TsdMetrics.buildMetric
73
+ metric.setGauge("myGauge", 20)
74
+ metric.close
75
+
76
+ # EMPTY metric
77
+ metric = TsdMetrics.buildMetric
78
+ metric.close
79
+
80
+ sleep(0.1)
81
+
82
+ checkFileForNWellFormedLines(2)
83
+ end
84
+ end
@@ -0,0 +1,99 @@
1
+ # Copyright 2014 Groupon.com
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
+ require "tsd_metrics/json_formatting_sink"
16
+ require "json"
17
+ require "json-schema"
18
+ require 'timecop'
19
+ require 'time'
20
+
21
+ describe "JsonFormattingSink" do
22
+ let(:outputStreamMock) do
23
+ mock = double()
24
+ end
25
+ let(:minimalStruct) do
26
+ {
27
+ gauges: {
28
+ "myGauge" => [{value: 4}]
29
+ },
30
+ timers: {
31
+ "myGauge" => [{value: 427297}]
32
+ },
33
+ counters: {
34
+ "myCounter" => [{value: 16238}, {value: 948}]
35
+ },
36
+ annotations: {
37
+ "myAnnotation" => "Nevermore, quoth the Raven",
38
+ initTimestamp: Time.parse("2014-11-02T03:33:38.000Z"),
39
+ finalTimestamp: Time.parse("2014-11-02T03:33:40.838Z")
40
+ }
41
+ }
42
+ end
43
+
44
+ let(:zeroSampleStruct) do
45
+ {
46
+ gauges: {
47
+ },
48
+ timers: {
49
+ },
50
+ counters: {
51
+ },
52
+ annotations: {
53
+ initTimestamp: 1393037729.0,
54
+ finalTimestamp: 1393037735.0
55
+ }
56
+ }
57
+ end
58
+ let(:receiver) { JsonFormattingSink.new(outputStreamMock) }
59
+
60
+ def captureOutput(metricStructMock)
61
+ json = nil
62
+ allow(outputStreamMock).to receive(:write) do |outputJson|
63
+ json = outputJson
64
+ end
65
+ receiver.receive(metricStructMock)
66
+ json
67
+ end
68
+
69
+ it "contains all the metric data" do
70
+
71
+ jsonString = captureOutput(double(minimalStruct))
72
+ expect(jsonString).to include("427297")
73
+ expect(jsonString).to include("16238")
74
+ expect(jsonString).to include("948")
75
+ expect(jsonString).to include('"Nevermore, quoth the Raven"')
76
+ expect(jsonString).to include('"2014-11-02T03:33:38.000Z"')
77
+ expect(jsonString).to include('"2014-11-02T03:33:40.838Z"')
78
+
79
+ end
80
+
81
+ it "includes the time as ISO8601 in UTC" do
82
+ timeString = '"2014-11-02T03:33:38.000Z"'
83
+ Timecop.freeze(Time.parse(timeString))
84
+
85
+ jsonString = captureOutput(double(minimalStruct))
86
+ expect(jsonString).to include(timeString)
87
+ Timecop.return
88
+ end
89
+
90
+ it "conforms to the JSON schema" do
91
+ jsonString = captureOutput(double(minimalStruct))
92
+ JSON::Validator.validate!("doc/query-log-schema-2e.json", jsonString)
93
+ end
94
+
95
+ it "does not output anything when no samples are present" do
96
+ expect(outputStreamMock).to_not receive(:write)
97
+ receiver.receive(double(zeroSampleStruct))
98
+ end
99
+ end