Skip to content

Commit 17c68d6

Browse files
committed
Merge branch 'release/0.4.0'
2 parents a99e264 + 33febfa commit 17c68d6

24 files changed

+406
-67
lines changed

CHANGELOG

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
Version 0.4.0 (2022-04-27)
2+
--------------------------
3+
Add back-off on 100% event sending failure (#9)
4+
Add event-level Subject (#61)
5+
Add IP address property to Subject (#62)
6+
Rename send_limit to batch_size in Emitter (#63)
7+
18
Version 0.3.0 (2022-04-19)
29
--------------------------
310
Add support for Linux in HTTP client (#5)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ This will create two executables - the first is the test-suite which can be exec
8484
The other is an example program which will send one of every type of event to an endpoint of your choosing like so:
8585

8686
```bash
87-
host> cd build
87+
host> cd build/example
8888
host> ./tracker_example {{ your collector uri }}
8989
```
9090

@@ -178,7 +178,7 @@ limitations under the License.
178178
[travis-image]: https://travis-ci.org/snowplow/snowplow-cpp-tracker.png?branch=master
179179
[travis]: https://travis-ci.org/snowplow/snowplow-cpp-tracker
180180

181-
[release-image]: https://img.shields.io/badge/release-0.3.0-6ad7e5.svg?style=flat
181+
[release-image]: https://img.shields.io/badge/release-0.4.0-6ad7e5.svg?style=flat
182182
[releases]: https://github.com/snowplow/snowplow-cpp-tracker/releases
183183

184184
[license-image]: https://img.shields.io/badge/license-Apache--2-blue.svg?style=flat

snowplow-cpp-tracker-example.vcxproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@
102102
<ClCompile Include="include\sqlite3.c" />
103103
<ClCompile Include="src\client_session.cpp" />
104104
<ClCompile Include="src\cracked_url.cpp" />
105-
<ClCompile Include="src\emitter.cpp" />
105+
<ClCompile Include="src\emitter\emitter.cpp" />
106+
<ClCompile Include="src\emitter\retry_delay.cpp" />
106107
<ClCompile Include="src\http\http_client_windows.cpp" />
107108
<ClCompile Include="src\http\http_request_result.cpp" />
108109
<ClCompile Include="src\payload\payload.cpp" />
@@ -125,7 +126,8 @@
125126
<ClInclude Include="src\client_session.hpp" />
126127
<ClInclude Include="src\constants.hpp" />
127128
<ClInclude Include="src\cracked_url.hpp" />
128-
<ClInclude Include="src\emitter.hpp" />
129+
<ClInclude Include="src\emitter\emitter.hpp" />
130+
<ClInclude Include="src\emitter\retry_delay.hpp" />
129131
<ClInclude Include="src\http\http_client.hpp" />
130132
<ClInclude Include="src\http\http_client_windows.hpp" />
131133
<ClInclude Include="src\http\http_request_result.hpp" />

snowplow-cpp-tracker-example.vcxproj.filters

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
<ClCompile Include="src\cracked_url.cpp">
2222
<Filter>Source Files</Filter>
2323
</ClCompile>
24-
<ClCompile Include="src\emitter.cpp">
24+
<ClCompile Include="src\emitter\emitter.cpp">
25+
<Filter>Source Files</Filter>
26+
</ClCompile>
27+
<ClCompile Include="src\emitter\retry_delay.cpp">
2528
<Filter>Source Files</Filter>
2629
</ClCompile>
2730
<ClCompile Include="src\http\http_client_windows.cpp">
@@ -86,7 +89,10 @@
8689
<ClInclude Include="src\cracked_url.hpp">
8790
<Filter>Header Files</Filter>
8891
</ClInclude>
89-
<ClInclude Include="src\emitter.hpp">
92+
<ClInclude Include="src\emitter\emitter.hpp">
93+
<Filter>Header Files</Filter>
94+
</ClInclude>
95+
<ClInclude Include="src\emitter\retry_delay.hpp">
9096
<Filter>Header Files</Filter>
9197
</ClInclude>
9298
<ClInclude Include="src\http\http_client.hpp">

snowplow-cpp-tracker.vcxproj

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@
106106
<ClCompile Include="include\sqlite3.c" />
107107
<ClCompile Include="src\client_session.cpp" />
108108
<ClCompile Include="src\cracked_url.cpp" />
109-
<ClCompile Include="src\emitter.cpp" />
109+
<ClCompile Include="src\emitter\emitter.cpp" />
110+
<ClCompile Include="src\emitter\retry_delay.cpp" />
110111
<ClCompile Include="src\http\http_client_windows.cpp" />
111112
<ClCompile Include="src\http\http_request_result.cpp" />
112113
<ClCompile Include="src\payload\payload.cpp" />
@@ -124,7 +125,8 @@
124125
<ClCompile Include="test\http\test_http_client.cpp" />
125126
<ClCompile Include="test\client_session_test.cpp" />
126127
<ClCompile Include="test\cracked_url_test.cpp" />
127-
<ClCompile Include="test\emitter_test.cpp" />
128+
<ClCompile Include="test\emitter\emitter_test.cpp" />
129+
<ClCompile Include="test\emitter\retry_delay_test.cpp" />
128130
<ClCompile Include="test\http\http_client_test.cpp" />
129131
<ClCompile Include="test\http\http_request_result_test.cpp" />
130132
<ClCompile Include="test\main.cpp" />
@@ -143,7 +145,8 @@
143145
<ClInclude Include="src\client_session.hpp" />
144146
<ClInclude Include="src\constants.hpp" />
145147
<ClInclude Include="src\cracked_url.hpp" />
146-
<ClInclude Include="src\emitter.hpp" />
148+
<ClInclude Include="src\emitter\emitter.hpp" />
149+
<ClInclude Include="src\emitter\retry_delay.hpp" />
147150
<ClInclude Include="src\http\http_client.hpp" />
148151
<ClInclude Include="src\http\http_client_windows.hpp" />
149152
<ClInclude Include="src\http\http_request_result.hpp" />

snowplow-cpp-tracker.vcxproj.filters

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
<ClCompile Include="src\cracked_url.cpp">
2222
<Filter>Source Files</Filter>
2323
</ClCompile>
24-
<ClCompile Include="src\emitter.cpp">
24+
<ClCompile Include="src\emitter\emitter.cpp">
25+
<Filter>Source Files</Filter>
26+
</ClCompile>
27+
<ClCompile Include="src\emitter\retry_delay.cpp">
2528
<Filter>Source Files</Filter>
2629
</ClCompile>
2730
<ClCompile Include="src\http\http_client_windows.cpp">
@@ -81,7 +84,10 @@
8184
<ClCompile Include="test\cracked_url_test.cpp">
8285
<Filter>Source Files</Filter>
8386
</ClCompile>
84-
<ClCompile Include="test\emitter_test.cpp">
87+
<ClCompile Include="test\emitter\emitter_test.cpp">
88+
<Filter>Source Files</Filter>
89+
</ClCompile>
90+
<ClCompile Include="test\emitter\retry_delay_test.cpp">
8591
<Filter>Source Files</Filter>
8692
</ClCompile>
8793
<ClCompile Include="test\http\http_client_test.cpp">
@@ -125,7 +131,10 @@
125131
<ClInclude Include="src\cracked_url.hpp">
126132
<Filter>Header Files</Filter>
127133
</ClInclude>
128-
<ClInclude Include="src\emitter.hpp">
134+
<ClInclude Include="src\emitter\emitter.hpp">
135+
<Filter>Header Files</Filter>
136+
</ClInclude>
137+
<ClInclude Include="src\emitter\retry_delay.hpp">
129138
<Filter>Header Files</Filter>
130139
</ClInclude>
131140
<ClInclude Include="src\http\http_client.hpp">

src/constants.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ using std::string;
2121
using std::set;
2222

2323
namespace snowplow {
24-
const string SNOWPLOW_TRACKER_VERSION_LABEL = "cpp-0.3.0";
24+
const string SNOWPLOW_TRACKER_VERSION_LABEL = "cpp-0.4.0";
2525

2626
// post requests
2727
const string SNOWPLOW_POST_PROTOCOL_VENDOR = "com.snowplowanalytics.snowplow";
@@ -70,6 +70,7 @@ const string SNOWPLOW_COLOR_DEPTH = "cd";
7070
const string SNOWPLOW_TIMEZONE = "tz";
7171
const string SNOWPLOW_LANGUAGE = "lang";
7272
const string SNOWPLOW_USERAGENT = "ua";
73+
const string SNOWPLOW_IP_ADDRESS = "ip";
7374

7475
// structured event
7576
const string SNOWPLOW_SE_CATEGORY = "se_ca";

src/emitter.cpp renamed to src/emitter/emitter.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,33 @@ using std::transform;
2626
using std::equal;
2727
using std::move;
2828
using std::future;
29+
using std::this_thread::sleep_for;
2930

3031
const int post_wrapper_bytes = 88; // "schema":"iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-4","data":[]
3132
const int post_stm_bytes = 22; // "stm":"1443452851000"
3233

3334
#if defined(__APPLE__)
34-
#include "http/http_client_apple.hpp"
35+
#include "../http/http_client_apple.hpp"
3536
unique_ptr<HttpClient> createDefaultHttpClient() {
3637
return unique_ptr<HttpClient>(new HttpClientApple());
3738
}
3839
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
39-
#include "http/http_client_windows.hpp"
40+
#include "../http/http_client_windows.hpp"
4041
unique_ptr<HttpClient> createDefaultHttpClient() {
4142
return unique_ptr<HttpClient>(new HttpClientWindows());
4243
}
4344
#else
44-
#include "http/http_client_curl.hpp"
45+
#include "../http/http_client_curl.hpp"
4546
unique_ptr<HttpClient> createDefaultHttpClient() {
4647
return unique_ptr<HttpClient>(new HttpClientCurl());
4748
}
4849
#endif
4950

50-
Emitter::Emitter(const string &uri, Method method, Protocol protocol, int send_limit,
51-
int byte_limit_post, int byte_limit_get, shared_ptr<EventStore> event_store) : Emitter(uri, method, protocol, send_limit, byte_limit_post, byte_limit_get, std::move(event_store), createDefaultHttpClient()) {
51+
Emitter::Emitter(const string &uri, Method method, Protocol protocol, int batch_size,
52+
int byte_limit_post, int byte_limit_get, shared_ptr<EventStore> event_store) : Emitter(uri, method, protocol, batch_size, byte_limit_post, byte_limit_get, std::move(event_store), createDefaultHttpClient()) {
5253
}
5354

54-
Emitter::Emitter(const string &uri, Method method, Protocol protocol, int send_limit,
55+
Emitter::Emitter(const string &uri, Method method, Protocol protocol, int batch_size,
5556
int byte_limit_post, int byte_limit_get, shared_ptr<EventStore> event_store, unique_ptr<HttpClient> http_client) : m_url(this->get_collector_url(uri, protocol, method)) {
5657

5758
if (uri == "") {
@@ -74,7 +75,7 @@ Emitter::Emitter(const string &uri, Method method, Protocol protocol, int send_l
7475

7576
this->m_running = false;
7677
this->m_method = method;
77-
this->m_send_limit = send_limit;
78+
this->m_batch_size = batch_size;
7879
this->m_byte_limit_post = byte_limit_post;
7980
this->m_byte_limit_get = byte_limit_get;
8081
this->m_event_store = move(event_store);
@@ -133,7 +134,7 @@ void Emitter::flush() {
133134
void Emitter::run() {
134135
do {
135136
list<EventRow> event_rows;
136-
m_event_store->get_event_rows_batch(&event_rows, m_send_limit);
137+
m_event_store->get_event_rows_batch(&event_rows, m_batch_size);
137138

138139
if (event_rows.size() > 0) {
139140
// emit the events
@@ -163,6 +164,19 @@ void Emitter::run() {
163164
delete_row_ids.splice(delete_row_ids.end(), success_row_ids);
164165
delete_row_ids.splice(delete_row_ids.end(), failed_wont_retry_row_ids);
165166
m_event_store->delete_event_rows_with_ids(delete_row_ids);
167+
168+
// update retry delay calculation based on whether the requests will be retried
169+
if (!failed_will_retry_row_ids.empty()) {
170+
m_retry_delay.will_retry_emit();
171+
} else {
172+
m_retry_delay.wont_retry_emit();
173+
}
174+
175+
// sleep for the retry delay if there is one
176+
auto retry_delay = m_retry_delay.get();
177+
if (retry_delay.count() > 0) {
178+
sleep_for(retry_delay);
179+
}
166180
} else {
167181
m_check_fin.notify_all();
168182

src/emitter.hpp renamed to src/emitter/emitter.hpp

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ See the Apache License Version 2.0 for the specific language governing permissio
2020
#include <future>
2121
#include <thread>
2222
#include <algorithm>
23-
#include "constants.hpp"
24-
#include "utils.hpp"
25-
#include "storage/event_store.hpp"
26-
#include "payload/payload.hpp"
27-
#include "payload/self_describing_json.hpp"
28-
#include "cracked_url.hpp"
29-
#include "http/http_request_result.hpp"
30-
#include "http/http_client.hpp"
23+
#include "../constants.hpp"
24+
#include "../utils.hpp"
25+
#include "../storage/event_store.hpp"
26+
#include "../payload/payload.hpp"
27+
#include "../payload/self_describing_json.hpp"
28+
#include "../cracked_url.hpp"
29+
#include "../http/http_request_result.hpp"
30+
#include "../http/http_client.hpp"
31+
#include "retry_delay.hpp"
3132

3233
using std::string;
3334
using std::thread;
@@ -91,12 +92,12 @@ class Emitter {
9192
* @param uri The URI to send events to
9293
* @param method The request type to use (GET or POST)
9394
* @param protocol The protocol to use (http or https)
94-
* @param send_limit The maximum amount of events to send at a time
95+
* @param batch_size The maximum amount of events to send at a time
9596
* @param byte_limit_post The byte limit when sending a POST request
9697
* @param byte_limit_get The byte limit when sending a GET request
9798
* @param event_store Defines the database to use for event queue
9899
*/
99-
Emitter(const string & uri, Method method, Protocol protocol, int send_limit,
100+
Emitter(const string & uri, Method method, Protocol protocol, int batch_size,
100101
int byte_limit_post, int byte_limit_get, shared_ptr<EventStore> event_store);
101102

102103
/**
@@ -105,13 +106,13 @@ class Emitter {
105106
* @param uri The URI to send events to
106107
* @param method The request type to use (GET or POST)
107108
* @param protocol The protocol to use (http or https)
108-
* @param send_limit The maximum amount of events to send at a time
109+
* @param batch_size The maximum amount of events to send at a time
109110
* @param byte_limit_post The byte limit when sending a POST request
110111
* @param byte_limit_get The byte limit when sending a GET request
111112
* @param event_store Defines the database to use for event queue
112113
* @param http_client Unique pointer to a custom HTTP client to send GET and POST requests with
113114
*/
114-
Emitter(const string & uri, Method method, Protocol protocol, int send_limit,
115+
Emitter(const string & uri, Method method, Protocol protocol, int batch_size,
115116
int byte_limit_post, int byte_limit_get, shared_ptr<EventStore> event_store, unique_ptr<HttpClient> http_client);
116117
~Emitter();
117118

@@ -152,11 +153,11 @@ class Emitter {
152153
Method get_method() const { return m_method; }
153154

154155
/**
155-
* @brief Get the send limit.
156+
* @brief Get the batch size.
156157
*
157158
* @return unsigned int The maximum amount of events to send at a time
158159
*/
159-
unsigned int get_send_limit() const { return m_send_limit; }
160+
unsigned int get_batch_size() const { return m_batch_size; }
160161

161162
/**
162163
* @brief Get the byte limit for GET.
@@ -208,7 +209,7 @@ class Emitter {
208209
Method m_method;
209210
shared_ptr<EventStore> m_event_store;
210211
unique_ptr<HttpClient> m_http_client;
211-
unsigned int m_send_limit;
212+
unsigned int m_batch_size;
212213
unsigned int m_byte_limit_get;
213214
unsigned int m_byte_limit_post;
214215

@@ -222,6 +223,7 @@ class Emitter {
222223
EmitterCallback m_callback;
223224
EmitStatus m_callback_emit_status;
224225
map<int, bool> m_custom_retry_for_status_codes;
226+
RetryDelay m_retry_delay;
225227

226228
void run();
227229
void do_send(const list<EventRow> &event_rows, list<HttpRequestResult> *results);

src/emitter/retry_delay.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
Copyright (c) 2022 Snowplow Analytics Ltd. All rights reserved.
3+
4+
This program is licensed to you under the Apache License Version 2.0,
5+
and you may not use this file except in compliance with the Apache License Version 2.0.
6+
You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7+
8+
Unless required by applicable law or agreed to in writing,
9+
software distributed under the Apache License Version 2.0 is distributed on an
10+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
14+
#include "retry_delay.hpp"
15+
#include <random>
16+
17+
using namespace snowplow;
18+
using std::min;
19+
20+
RetryDelay::RetryDelay(double base, double factor, int retry_count_cap, double jitter) {
21+
m_base = base;
22+
m_factor = factor;
23+
m_retry_count_cap = retry_count_cap;
24+
m_jitter = jitter;
25+
m_retry_count = 0;
26+
}
27+
28+
void RetryDelay::will_retry_emit() {
29+
m_retry_count++;
30+
}
31+
32+
void RetryDelay::wont_retry_emit() {
33+
m_retry_count = 0;
34+
}
35+
36+
milliseconds RetryDelay::get() const {
37+
if (m_retry_count == 0) {
38+
return milliseconds(0);
39+
}
40+
41+
double delay_ms = m_base * pow(m_factor, min(m_retry_count, m_retry_count_cap) - 1);
42+
43+
if (m_jitter != 0) {
44+
std::random_device rd;
45+
std::mt19937 mt(rd());
46+
std::uniform_real_distribution<double> dist(0.0, 1.0);
47+
double seed = dist(mt);
48+
double deviation = floor(seed * m_jitter * delay_ms);
49+
50+
if (round(seed) == 1) {
51+
delay_ms -= deviation;
52+
} else {
53+
delay_ms += deviation;
54+
}
55+
}
56+
57+
return milliseconds((unsigned long) delay_ms);
58+
}

0 commit comments

Comments
 (0)