apptrail-application-events-sdk 0.0.1 → 0.0.5

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
  SHA256:
3
- metadata.gz: 0a56d565f6da67bd2bc4bbfb36c20f599e0ef18bd7ec0f5e969caae6c592409c
4
- data.tar.gz: b3c67d43208b9a8eb134bb529d023c33c24bae80b4485ed41dcc6ca224865131
3
+ metadata.gz: 033ced91d5d347d03c478bfd99656e901920d6eadb8823b19fd0b5751ac3b736
4
+ data.tar.gz: 38f63305471ef6aa3ea25392df9c5b72676b3410ab4d6ec5055c8d1597f655e2
5
5
  SHA512:
6
- metadata.gz: 9955cd66982d262361d7cbfdd6672ce4f34ff03e4caf65fc883ddcede9ba0fc2d3386b7fe93e32e2f1cbeed1fc0ee3f1d4450c87131eb7e94491ce6f182ed5ce
7
- data.tar.gz: 76618a0b1bd9f2800a37f167b2781210664da5bb4458a4be29c50d842d14d0e8c2f46bdafd4c3d353e1652625c08bd3062c007233a18b763c5f373a01010a0ce
6
+ metadata.gz: efe5076ba194024da52d8b9305fcaf7319717243eab7f2bba2320cfdb31eb353b194d4ee7fd350295e43520dfaedfa8cf5b4c881a3c2aecccc602527e82e31e9
7
+ data.tar.gz: 288c4f04e2508aaa7636d685dc14c873382f597ab96a7a83db99f0e2097580671cff16ff6c7bf7ade18e457757d0145c7593a60d10982a9176ce457091accf1c
data/README.md CHANGED
@@ -62,8 +62,10 @@ event = {
62
62
  },
63
63
  },
64
64
  ],
65
- sourceIpAddress: "103.6.179.245",
66
- userAgent: "Apache-HttpClient/4.5.3 (Java/11.0.11)",
65
+ context: {
66
+ sourceIpAddress: "103.6.179.245",
67
+ userAgent: "Apache-HttpClient/4.5.3 (Java/11.0.11)"
68
+ },
67
69
  tags: {
68
70
  severity: "LOW",
69
71
  },
@@ -1,13 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
  require 'stringio'
3
- require "base64"
4
- require "json"
5
+ require 'base64'
6
+ require 'json'
5
7
  require 'securerandom'
6
- require "http"
7
- require "json-schema"
8
- require "retriable"
9
-
10
- #HTTP.default_options = HTTP::Options.new(features: {logging: { logger: Logger.new(STDOUT)}})
8
+ require 'http'
9
+ require 'json-schema'
10
+ require 'retriable'
11
11
 
12
12
  module Apptrail
13
13
  class << self
@@ -15,15 +15,13 @@ module Apptrail
15
15
  # For example, log to STDOUT by setting this to Logger.new(STDOUT).
16
16
  #
17
17
  # @return [Logger]
18
- attr_accessor :logger
18
+ attr_writer :logger
19
19
 
20
20
  def logger
21
21
  @logger ||= Logger.new($stdout).tap do |log|
22
- log.progname = self.name
22
+ log.progname = name
23
23
  end
24
24
  end
25
-
26
-
27
25
  end
28
26
 
29
27
  class ApptrailError < StandardError; end
@@ -34,10 +32,19 @@ module Apptrail
34
32
  tries: 3,
35
33
  base_interval: 0.04,
36
34
  on: Apptrail::ApptrailRetryableError,
37
- on_retry: Proc.new { puts 'Retrying...' },
35
+ on_retry: proc { Apptrail.logger.debug('Retrying upload.') },
36
+ max_interval: 0.12,
37
+ max_elapsed_time: 4,
38
+ rand_factor: 0.2
39
+ }
40
+ c.contexts[:session] = {
41
+ tries: 3,
42
+ base_interval: 0.04,
43
+ on: Apptrail::ApptrailRetryableError,
44
+ on_retry: proc { Apptrail.logger.debug('Retrying refresh session.') },
38
45
  max_interval: 0.12,
39
46
  max_elapsed_time: 4,
40
- rand_factor: 0.2,
47
+ rand_factor: 0.2
41
48
  }
42
49
  end
43
50
 
@@ -46,12 +53,9 @@ module Apptrail
46
53
  #
47
54
  # See [Sending events](https://apptrail.com/docs/applications/guide/working-with-events/overview).
48
55
  class ApptrailEventsClient
49
- @_form_data = nil
50
- @_upload_url = nil
51
-
52
56
  SCHEMA = JSON.parse(File.read(
53
- File.expand_path('../raw-event-schema.json', __FILE__)
54
- )).freeze
57
+ File.expand_path('raw-event-schema.json', __dir__)
58
+ )).freeze
55
59
  private_constant :SCHEMA
56
60
 
57
61
  def inspect
@@ -59,21 +63,29 @@ module Apptrail
59
63
  end
60
64
 
61
65
  def to_s
62
- "ApptrailEventsClient{}"
66
+ 'ApptrailEventsClient{}'
63
67
  end
64
68
 
65
69
  def initialize(region:, api_key:)
66
70
  @_region = region
67
71
  begin
68
72
  parsed_key = Base64.urlsafe_decode64(api_key)
69
- application_id, *_ = parsed_key.split(',', 3)
73
+ application_id, = parsed_key.split(',', 3)
70
74
  @_application_id = application_id
71
- rescue
72
- raise ArgumentError, "Invalid API Key."
75
+ rescue StandardError
76
+ raise ArgumentError, 'Invalid API Key.'
73
77
  end
74
78
 
75
79
  @_base_api_url = "https://events.#{region}.apptrail.com/applications/session"
76
80
  @_api_key = api_key
81
+ @_session_client = HTTP.persistent @_base_api_url
82
+
83
+ @_form_data = nil
84
+ @_upload_url = nil
85
+ @_upload_client = nil
86
+
87
+ @_finalize_id = SecureRandom.uuid
88
+ ObjectSpace.define_finalizer(@_finalize_id, proc { close })
77
89
  end
78
90
 
79
91
  # Send a single audit event to log to Apptrail.
@@ -83,88 +95,109 @@ module Apptrail
83
95
  put_events([event])
84
96
  end
85
97
 
86
-
87
98
  # Send a list of up to 1000 audit events to log to Apptrail.
88
99
  #
89
100
  # @param events [Array<ApptrailEvent>]] An array of events to log. See [Apptrail Event Format](https://apptrail.com/docs/applications/guide/event-format) for a full description of the event format.
90
101
  def put_events(events)
91
- unless events.is_a?(Array)
92
- raise TypeError, "Must pass in array of events."
93
- end
94
- unless events.length <= 1000
95
- raise ArgumentError, "Can not send more than 1000 events in a single PutEvents call."
96
- end
102
+ raise TypeError, 'Must pass in array of events.' unless events.is_a?(Array)
103
+ raise ArgumentError, 'Can not send more than 1000 events in a single PutEvents call.' unless events.length <= 1000
97
104
 
98
105
  begin
99
- JSON::Validator.validate!(SCHEMA, events, :list => true, :parse_data => false)
106
+ JSON::Validator.validate!(SCHEMA, events, list: true, parse_data: false)
100
107
  rescue JSON::Schema::ValidationError => e
101
- raise Apptrail::ApptrailError.new(e.message)
108
+ raise Apptrail::ApptrailError, e.message
102
109
  end
103
110
 
104
- if @_upload_url.nil? || @_form_data.nil?
105
- _refresh_post_policy()
106
- end
111
+ _refresh_post_policy() if @_upload_url.nil? || @_form_data.nil? || @_upload_client.nil?
107
112
 
108
- content = ""
113
+ content = StringIO.new
109
114
  events.each do |evt|
110
- content << JSON.generate(evt)
115
+ content << JSON.fast_generate(evt)
111
116
  content << "\n"
112
117
  end
113
118
 
114
- filename = SecureRandom.uuid + ".jsonl"
119
+ filename = "#{SecureRandom.uuid}.jsonl"
115
120
  s3_key = File.join(@_application_id, filename)
116
121
 
117
- form_file = HTTP::FormData::File.new(StringIO.new(content), :filename => filename)
122
+ form_file = HTTP::FormData::File.new(StringIO.new(content.string), filename: filename)
118
123
 
119
124
  new_form_opts = {
120
125
  **@_form_data,
121
- :key => s3_key,
122
- :file => form_file
126
+ key: s3_key,
127
+ file: form_file
123
128
  }
124
129
 
130
+ resp = nil
125
131
  begin
126
132
  Retriable.with_context(:s3) do
127
- resp = HTTP.post(@_upload_url, :form => new_form_opts)
128
- if !resp.status.success?
129
- if (resp.status.server_error?)
130
- raise ApptrailRetryableError.new("Server Error while putting events.")
131
- elsif (resp.status.client_error?)
132
- if (resp.status.code === 403 && resp.body.to_s.include?("Policy expired"))
133
- _refresh_post_policy()
134
- raise ApptrailRetryableError.new("Session expired.")
133
+ resp = @_upload_client.post(@_upload_url, form: new_form_opts)
134
+ unless resp.status.success?
135
+ if resp.status.server_error?
136
+ raise ApptrailRetryableError, 'Server Error while putting events.'
137
+ elsif resp.status.client_error?
138
+ if resp.status.code == 403 && resp.body.to_s.include?('Policy expired')
139
+ _refresh_post_policy
140
+ raise ApptrailRetryableError, 'Session expired.'
135
141
  else
136
- puts resp.body.to_s
137
- raise ApptrailError.new("Error while putting events.")
142
+ raise ApptrailError, 'Error while putting events.'
138
143
  end
139
144
  else
140
- raise ApptrailError.new("Error while putting events.")
145
+ raise ApptrailError, 'Error while putting events.'
141
146
  end
142
147
  end
143
148
  end
144
- rescue
145
- raise ApptrailError.new("Failed to put #{events.length} events. Encountered error.")
149
+ rescue StandardError
150
+ raise ApptrailError, "Failed to put #{events.length} events. Encountered error."
146
151
  else
147
- Apptrail::logger.info("Successfully wrote #{events.length} events.")
152
+ Apptrail.logger.info("Successfully wrote #{events.length} events.")
153
+ ensure
154
+ resp.flush if resp
148
155
  end
156
+ end
149
157
 
158
+ def close
159
+ # https://github.com/appsignal/rdkafka-ruby/pull/160/files
160
+ ObjectSpace.undefine_finalizer(@_finalize_id)
161
+ @_session_client.close if @_session_client
162
+ @_upload_client.close if @_upload_client
150
163
  end
151
164
 
152
165
  private
153
166
 
154
167
  def _refresh_post_policy
155
- puts @_base_api_url
156
- resp = HTTP
157
- .auth("Bearer #{@_api_key}")
158
- .get(@_base_api_url)
159
- if !resp.status.success?
160
- raise ApptrailError.new("Error refreshing credentials, status code: #{resp.code}")
168
+ fail_default = -> { raise ApptrailError, "Error refreshing credentials." }
169
+ resp = nil
170
+
171
+ begin
172
+ Retriable.with_context(:session) do
173
+ resp = @_session_client
174
+ .auth("Bearer #{@_api_key}")
175
+ .get(@_base_api_url)
176
+
177
+ unless resp.status.success?
178
+ if resp.status.server_error?
179
+ raise ApptrailRetryableError, 'Server Error refreshing session.'
180
+ elsif resp.status.client_error?
181
+ if resp.status.code == 429
182
+ raise ApptrailRetryableError, 'Throttling'
183
+ else
184
+ fail_default.call
185
+ end
186
+ else
187
+ fail_default.call
188
+ end
189
+ end
190
+
191
+ result = JSON.parse(resp.body.to_s)
192
+ @_upload_url = result['uploadUrl']
193
+ @_form_data = result['form']
194
+ @_upload_client = HTTP.persistent @_upload_url
195
+ end
196
+ rescue StandardError => e
197
+ fail_default.call
198
+ ensure
199
+ resp.flush if resp
161
200
  end
162
- result = JSON.parse(resp.body.to_s)
163
- @_upload_url = result["uploadUrl"]
164
- @_form_data = result["form"]
165
201
  end
166
-
167
-
168
202
  end
169
-
170
203
  end
@@ -53,21 +53,27 @@
53
53
  }
54
54
  }
55
55
  },
56
- "sourceIpAddress": {
57
- "type": "string",
58
- "description": "The IP address the activity/request being recorded was made from.",
59
- "oneOf": [
60
- {
61
- "format": "ipv4"
56
+ "context": {
57
+ "type": "object",
58
+ "description": "The context object contains fields that give customers additional information about the environment in and source from which the activity recorded occurred",
59
+ "properties": {
60
+ "sourceIpAddress": {
61
+ "type": "string",
62
+ "description": "The IP address the activity/request being recorded was made from.",
63
+ "anyOf": [
64
+ {
65
+ "format": "ipv4"
66
+ },
67
+ {
68
+ "format": "ipv6"
69
+ }
70
+ ]
62
71
  },
63
- {
64
- "format": "ipv6"
72
+ "userAgent": {
73
+ "type": "string",
74
+ "description": "The agent through which the request was made, e.g. `Mozilla/5.0` or `python-requests/2.20.1`."
65
75
  }
66
- ]
67
- },
68
- "userAgent": {
69
- "type": "string",
70
- "description": "The agent through which the request was made, e.g. `Mozilla/5.0` or `python-requests/2.20.1`."
76
+ }
71
77
  },
72
78
  "eventDetails": {
73
79
  "type": "object",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apptrail-application-events-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Apptrail Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-27 00:00:00.000000000 Z
11
+ date: 2022-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http