apptrail-application-events-sdk 0.0.1 → 0.0.5

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 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