l2meter 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b8cfc00c1a6cbda74012122b4e767ae10e8721d
4
- data.tar.gz: 6f9e05a2828f438d5a7105bbca3cd78ce4b78fc9
3
+ metadata.gz: 865b41102fd7ebcd25b127d1e1bdd4d3a777fa05
4
+ data.tar.gz: cfd0071e73ec174fda966428c1f9421f8db1758f
5
5
  SHA512:
6
- metadata.gz: b067f592722b372bfd78ff272a72fa50adb5adf73a169db08d5084c98888e51d803f707dd73511f38ddc1c2f6e44997376d9b920719cd13c666ab3ce42a31762
7
- data.tar.gz: 222b0436a4c08bc6cd7f5dbfd58cb2ddb64f7ddca2b60d7f45eecfc8e8f3994ec6cffdb91bc4fee49d6096843f2efe7ab0ca5e60f703ac82a540e99f631ae962
6
+ metadata.gz: afebdeaec22a78f58b14b66156e0804a961c34f84b0cced488c0185d90acba204d9921bd904522a5a58720bc29ea6207432afd5ead81b3f758e20e609a083383
7
+ data.tar.gz: 1eb3117c0347549685dd6cb4b0ac4b85bf2d02656a533b928509c88467c6e9f8bb72ea736ec5d34ef09ef5a37d1eabafd3b7f21e3a5f77f9af63f4945877afd1
data/README.md CHANGED
@@ -1,35 +1,185 @@
1
1
  # L2meter
2
+ [![Gem Version](https://img.shields.io/gem/v/l2meter.svg)](https://rubygems.org/gems/l2meter)
3
+ [![Build Status](https://img.shields.io/travis/heroku/l2meter.svg)](http://travis-ci.org/heroku/l2meter)
4
+ [![Code Climate](https://img.shields.io/codeclimate/github/heroku/l2meter.svg)](https://codeclimate.com/github/heroku/l2meter)
2
5
 
3
- L2meter is a little gem that helps you build loggers that outputs things in l2met format.
6
+ L2meter is a little gem that helps you build loggers that outputs things in
7
+ l2met-friendly format.
4
8
 
5
- ### Usage
9
+ ### Basics
10
+
11
+ A new logger might be created like so:
12
+
13
+ ```ruby
14
+ metrics = L2meter.build
15
+ ```
16
+
17
+ If you plan to use it globally across different components of your app,consider
18
+ making it constant.
19
+
20
+ The base `log` method accepts two type of things: bare values and key-value
21
+ pairs in form of hashes.
6
22
 
7
23
  ```ruby
8
- Metrics = L2meter.build do |config|
9
- # sort output tokens, false by default
10
- config.sort = true
24
+ metrics.log "Hello world" # => hello-world
25
+ metrics.log :db_query, result: :success # => db-query result=success
26
+ ```
27
+
28
+ It can also take a block. In this case the message will be emitted twice, once
29
+ at the start of the execution and another at the end. The end result might look
30
+ like so:
11
31
 
12
- # default context
13
- config.context = { name: "my-app-name" }
32
+ ```ruby
33
+ metrics.log :doing_work do # => doing-work at=start
34
+ do_some_work #
35
+ metrics.log :work_done # => work-done
36
+ end # => doing-work at=finish elapsed=1.2345s
37
+ ```
14
38
 
15
- # ... or dynamic context
16
- config.context do
17
- { random_thing: SecureRandom.uuid }
39
+ In case the exception is raised inside the block, l2meter will report is like
40
+ so:
41
+
42
+ ```ruby
43
+ metrics.log :doing_work do # => doing-work
44
+ raise ArgumentError, \ #
45
+ "something is wrong" #
46
+ end # => doing-work at=exception exception=ArgumentError message="something is wrong" elapsed=1.2345s
47
+ ```
48
+
49
+ ## Context
50
+
51
+ L2meter allows setting context for a block. It might work something like this:
52
+
53
+ ```ruby
54
+ def do_work_with_retries
55
+ attempt = 1
56
+ begin
57
+ metrics.context attempt: attempt do
58
+ do_some_work # => doing-work attempt=1
59
+ # => doing-work attempt=2
60
+ # => doing-work attempt=3
61
+ end
62
+ rescue => error
63
+ attempt += 1
64
+ retry
18
65
  end
66
+ end
67
+ ```
19
68
 
20
- # $stdout by default
21
- config.output = StringIO.new
69
+ L2meter supports dynamic contexts as well. You can pass a proc instead of raw
70
+ value in porder to use it.
71
+
72
+ The same example as above could be written like ths instead:
73
+
74
+ ```ruby
75
+ def do_work_with_retries
76
+ attempt = 1
77
+ metrics.context ->{{ attempt: attempt }} do
78
+ begin
79
+ do_some_work
80
+ rescue => error
81
+ attempt +=1
82
+ retry
83
+ end
84
+ end
22
85
  end
86
+ ```
87
+
88
+ ## Other
89
+
90
+ Some other l2met-specific methods are supported.
91
+
92
+ ```ruby
93
+ metrics.count :user_registered # => count#user-registered=1
94
+ metrics.count :registered_users, 10 # => count#registered-users=10
23
95
 
24
- Metrics.log "Hello world" # => hello-world
96
+ metrics.measure :connection_count, 20, # => measure#connection-count=235
97
+ metrics.measure :db_query, 235, unit: :ms, # => measure#db-query.ms=235
98
+
99
+ metrics.sample :connection_count, 20, # => sample#connection-count=235
100
+ metrics.sample :db_query, 235, unit: :ms, # => sample#db-query.ms=235
101
+
102
+ metrics.unique :user, "bob@example.com" # => unique#user=bob@example.com
103
+ ```
104
+
105
+ ### Configuration
106
+
107
+ L2meter supports configurtion. Here's how you cna configure things:
108
+
109
+ ```ruby
110
+ metrics = L2meter.build do |config|
111
+ # configuration happen here
112
+ end
113
+ ```
25
114
 
26
- Metrics.log :foo, :bar, fizz: :buzz # => foo bar fizz=buzz
115
+ These are available configuration:
27
116
 
28
- Metrics.log :doing_work do # => doing-work at=start
29
- do_some_work #
30
- end # => doing-work at=finish elapsed=3.1234s
117
+ #### Global context
31
118
 
32
- Metrics.log :deez_nutz do # => deez-nutz at=start
33
- raise ArgumentError, "error here" #
34
- end # => deez-nutz at=exception exception=ArgumentError message="error here" elapsed=1.2345s
119
+ Global context works similary to context method, but globally:
120
+
121
+ ```ruby
122
+ config.context = { app_name: "my-app-name" }
123
+
124
+ # ...
125
+
126
+ metrics.log foo: :bar # => app-name=my-app-name foo-bar
127
+ ```
128
+
129
+ Dynamic context is also supported:
130
+
131
+ ```ruby
132
+ context.context do
133
+ { request_id: CurrentContext.request_id }
134
+ end
135
+ ```
136
+
137
+ #### Sorting
138
+
139
+ By default l2meter doesn't sort tokens before output, putting them in the order
140
+ they're passed. But you can make it sorted like so:
141
+
142
+ ```ruby
143
+ config.sort = true
144
+
145
+ # ...
146
+
147
+ metrics.log :c, :b, :a # => a b c
148
+ ```
149
+
150
+ #### Source
151
+
152
+ Source is a special parameter that'll be appended to all emitted messages.
153
+
154
+ ```ruby
155
+ config.source = "production"
156
+
157
+ # ...
158
+
159
+ metrics.log foo: :bar # => source=production foo=bar
160
+ ```
161
+
162
+ ## Silence
163
+
164
+ There's a way to temporary silence the log emitter. This might be userful for
165
+ tests for example.
166
+
167
+ ```ruby
168
+ metrics.silence do
169
+ # logger is completely silenced
170
+ metrics.log "hello world" # nothing is emitted here
171
+ end
172
+
173
+ # works normally again
174
+ metrics.log :foo # => foo
175
+ ```
176
+
177
+ The typical setup for RSpec might look like this:
178
+
179
+ ```ruby
180
+ RSpec.configure do |config|
181
+ config.around :each do |example|
182
+ Metrics.silence &example
183
+ end
184
+ end
35
185
  ```
@@ -1,6 +1,12 @@
1
1
  module L2meter
2
2
  class Configuration
3
3
  attr_writer :output
4
+ attr_accessor :source
5
+ attr_reader :contexts
6
+
7
+ def initialize
8
+ @contexts = []
9
+ end
4
10
 
5
11
  def output
6
12
  @output ||= $stdout
@@ -8,7 +14,7 @@ module L2meter
8
14
 
9
15
  def key_formatter
10
16
  @key_formatter ||= ->(key) do
11
- key.to_s.strip.downcase.gsub(/[^-a-z\d]+/, ?-)
17
+ key.to_s.strip.downcase.gsub(/[^-a-z\d.#]+/, ?-)
12
18
  end
13
19
  end
14
20
 
@@ -36,16 +42,11 @@ module L2meter
36
42
  end
37
43
 
38
44
  def context(&block)
39
- @context_block = block
40
- end
41
-
42
- def context=(value)
43
- @static_context = value
45
+ @contexts = [block]
44
46
  end
45
47
 
46
- def get_context
47
- return @static_context if @static_context
48
- @context_block ? @context_block.call.to_h : {}
48
+ def context=(block_or_value)
49
+ @contexts = [block_or_value]
49
50
  end
50
51
  end
51
52
  end
@@ -6,10 +6,12 @@ module L2meter
6
6
  @configuration = configuration
7
7
  end
8
8
 
9
- def log(*args, **params)
9
+ def log(*args)
10
+ params = Hash === args.last ? args.pop : {}
10
11
  args = args.map { |key| [ key, true ] }.to_h
11
12
  params = args.merge(params)
12
- params = context.merge(params)
13
+ params = current_context.merge(params)
14
+ params = merge_source(params)
13
15
 
14
16
  if block_given?
15
17
  wrap params, &Proc.new
@@ -26,23 +28,75 @@ module L2meter
26
28
  configuration.output = output
27
29
  end
28
30
 
31
+ def measure(metric, value, unit: nil)
32
+ metric = [metric, unit].compact * ?.
33
+ log_with_prefix :measure, metric, value
34
+ end
35
+
36
+ def sample(metric, value, unit: nil)
37
+ metric = [metric, unit].compact * ?.
38
+ log_with_prefix :sample, metric, value
39
+ end
40
+
41
+ def count(metric, value=1)
42
+ log_with_prefix :count, metric, value
43
+ end
44
+
45
+ def unique(metric, value)
46
+ log_with_prefix :unique, metric, value
47
+ end
48
+
49
+ def context(hash_or_proc)
50
+ configuration_contexts.push hash_or_proc
51
+ yield
52
+ ensure
53
+ configuration_contexts.pop
54
+ end
55
+
29
56
  private
30
57
 
31
- def context
32
- configuration.get_context
58
+ def configuration_contexts
59
+ configuration.contexts
60
+ end
61
+
62
+ def merge_source(params)
63
+ source = configuration.source
64
+ source ? { source: source }.merge(params) : params
65
+ end
66
+
67
+ def current_context
68
+ configuration_contexts.inject({}) do |result, c|
69
+ current = c.respond_to?(:call) ? c.call.to_h : c.clone
70
+ result.merge(current)
71
+ end
72
+ end
73
+
74
+ def format_value(value)
75
+ configuration.value_formatter.call(value)
76
+ end
77
+
78
+ def format_key(key)
79
+ configuration.key_formatter.call(key)
80
+ end
81
+
82
+ def format_keys(params)
83
+ params.inject({}) do |normalized, (key, value)|
84
+ normalized.tap { |n| n[format_key(key)] = value }
85
+ end
33
86
  end
34
87
 
35
88
  def write(params)
36
- tokens = params.map do |key, value|
37
- key = configuration.key_formatter.call(key)
38
- next key if value == true
39
- value = configuration.value_formatter.call(value)
40
- [ key, value ] * ?=
89
+ tokens = format_keys(params).map do |key, value|
90
+ value == true ? key : [ key, format_value(value) ] * ?=
41
91
  end
42
92
 
43
93
  tokens.sort! if configuration.sort?
44
94
 
45
- configuration.output.puts tokens.join(" ")
95
+ configuration.output.print tokens.join(" ") + "\n"
96
+ end
97
+
98
+ def log_with_prefix(prefix, key, value)
99
+ log Hash["#{prefix}##{key}", value]
46
100
  end
47
101
 
48
102
  def wrap(params)
@@ -1,3 +1,3 @@
1
1
  module L2meter
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.3".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: l2meter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Pravosud
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-10 00:00:00.000000000 Z
11
+ date: 2015-09-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: