mn_utils_gem 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 419e0bfbbf1a78e1c98adcfbb2a9bfac214572f1cfd6c3f7f3b3a261e3e58e2d
4
+ data.tar.gz: bc949046b18e79169aeb93231177fbbcb518fb920d45391a90900e781c7695b6
5
+ SHA512:
6
+ metadata.gz: f6d4f8e1121c6667735824ed70cdd2f5069dcadd8f7fa2cb01c75c6c008d1187a8a507c79c58a15e573e52891163975206ce226e2c9c15f6217f8f998d550086
7
+ data.tar.gz: d9e34a791f3d3c392d23d6ed3fe0f3da90f6413ba2d1da9ff26a898e6d8798629409f252e0384d3753a63f65e1e88fb49044f4fd59517b05dc75df57fd7c4223
@@ -0,0 +1,144 @@
1
+ require 'gelf'
2
+ require 'aws-sdk-cloudwatch'
3
+ require 'request_store'
4
+ require 'singleton'
5
+
6
+ # SiteAction class to log important site actions to Graylog
7
+ # and send a matching metric to Cloudwatch
8
+ #
9
+ # usage: MnUtils::SiteAction.instance.log(message, site_action, optional_payload)
10
+ #
11
+ # eg: MnUtils::SiteAction.instance.log(
12
+ # "Login attempted with non-existent email",
13
+ # :login_attempt_nonexistent_email,
14
+ # {_email: "fish@banana.com", _request_ip: "123.123.123.123"}
15
+ # )
16
+ # This logs all the details in Graylog and records a count of 1
17
+ # against a Cloudwatch metric called login_attempt_nonexistent_email in namespace mn/auth
18
+ #
19
+ # The optional payload should be a simple flat hash with all keys starting
20
+ # with an underscore _ and all values being strings
21
+
22
+ module MnUtils
23
+ class SiteAction
24
+
25
+ include Singleton
26
+
27
+ def initialize
28
+ # add new site actions here under the relevant group
29
+ # NO DUPLICATES please - a site action can only exist under one group
30
+ @_site_actions_and_groups = {
31
+ test: [
32
+ :test_event_1,
33
+ :test_event_2
34
+ ],
35
+ reg: [
36
+ :reg_success_via_email,
37
+ :reg_success_via_google,
38
+ :reg_success_via_facebook,
39
+ :reg_attempt_invalid_email,
40
+ :reg_attempt_invalid_password,
41
+ :reg_attempt_invalid_username,
42
+ ],
43
+ auth: [
44
+ :login_success_via_email,
45
+ :login_success_via_google,
46
+ :login_success_via_facebook,
47
+ :login_attempt_invalid_email,
48
+ :login_attempt_nonexistent_email,
49
+ :login_attempt_invalid_password,
50
+ :login_attempt_incorrect_password,
51
+ ],
52
+ }.freeze
53
+
54
+ # this creates a reverse map of all site actions and their corresponding group
55
+ # for quick lookups by the code
56
+ @_site_action_group_map = Hash[*(@_site_actions_and_groups.map {|k,v| v.map {|x| [x, k]}}.flatten)].freeze
57
+ end
58
+
59
+ def log(message, site_action, payload = {})
60
+
61
+ # validate the parameters
62
+ raise ArgumentError, 'message cannot be blank' \
63
+ if message.blank?
64
+ raise ArgumentError, 'site_action must be a symbol' \
65
+ unless site_action.is_a?(Symbol)
66
+ raise ArgumentError, 'payload must be a hash' \
67
+ unless payload.is_a?(Hash)
68
+ raise ArgumentError, 'site_action value is not in allowed list' \
69
+ unless @_site_action_group_map.key? site_action
70
+
71
+ # validate the payload hash
72
+ payload.each do |key, value|
73
+ raise ArgumentError, "payload key #{key} must be a symbol" \
74
+ unless key.is_a?(Symbol)
75
+ key_string = key.to_s
76
+ raise ArgumentError, "payload key #{key} must begin with an underscore" \
77
+ unless key_string.chars.first == '_'
78
+ raise ArgumentError, "payload key #{key} must be at least 2 characters long" \
79
+ unless key_string.length >= 2
80
+ raise ArgumentError, "payload key cannot be _id" \
81
+ if key_string == '_id'
82
+ raise ArgumentError, "payload value for key #{key} must be a string" \
83
+ unless value.is_a?(String)
84
+ end
85
+
86
+ # validate the environment variables we need
87
+ raise ArgumentError, "ENV['SRV_CODE'] cannot be blank" \
88
+ unless ENV.key? 'SRV_CODE'
89
+
90
+ # setup the full payload
91
+ full_payload = payload.dup
92
+ full_payload[:short_message] = message
93
+ full_payload[:_site_action_group] = @_site_action_group_map[site_action]
94
+ full_payload[:_site_action] = site_action
95
+ full_payload[:_srv_code] = ENV['SRV_CODE']
96
+
97
+ # add the request ID if available
98
+ if RequestStore.store[:request_id]
99
+ full_payload[:_request_id] = RequestStore.store[:request_id]
100
+ end
101
+
102
+ # send it off
103
+ send_to_graylog full_payload
104
+ send_to_cloudwatch full_payload
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def send_to_graylog(payload)
111
+ if ENV.key?('GRAYLOG_GELF_UDP_HOST') && ENV.key?('GRAYLOG_GELF_UDP_PORT')
112
+ n = GELF::Notifier.new(ENV['GRAYLOG_GELF_UDP_HOST'], ENV['GRAYLOG_GELF_UDP_PORT'])
113
+ n.notify! payload
114
+ else
115
+ Rails.logger.debug("Payload for Graylog: #{payload}")
116
+ end
117
+ rescue Exception => e
118
+ Rails.logger.error e
119
+ end
120
+
121
+ def send_to_cloudwatch(payload)
122
+ metric_name = payload[:_site_action]
123
+ metric_data = [{
124
+ metric_name: metric_name,
125
+ value: 1,
126
+ unit: "Count"
127
+ }]
128
+ if ENV.key?'CLOUDWATCH_ROOT_NAMESPACE'
129
+ root_namespace = ENV['CLOUDWATCH_ROOT_NAMESPACE']
130
+ second_namespace = payload[:_site_action_group]
131
+ namespace = "#{root_namespace}/#{second_namespace}"
132
+ cw = Aws::CloudWatch::Client.new
133
+ cw.put_metric_data({
134
+ namespace: namespace,
135
+ metric_data: metric_data
136
+ })
137
+ else
138
+ Rails.logger.debug("Payload for Cloudwatch #{metric_data}")
139
+ end
140
+ rescue Exception => e
141
+ Rails.logger.error e
142
+ end
143
+
144
+ end
@@ -0,0 +1,3 @@
1
+ module MnUtilsGem
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "mn_utils_gem/version"
2
+
3
+ module MnUtilsGem
4
+ class Error < StandardError; end
5
+ # Your code goes here...
6
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mn_utils_gem
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Shamim Mirzai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gelf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-cloudwatch
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: request_store
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.17'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.17'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ description:
98
+ email:
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - lib/mn_utils_gem.rb
104
+ - lib/mn_utils_gem/site_action.rb
105
+ - lib/mn_utils_gem/version.rb
106
+ homepage: https://github.com/mumsnet/mn_utils_gem
107
+ licenses: []
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 3.0.3
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Mumsnet utils gem for microservices
128
+ test_files: []