turnstile-rb 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require_relative '../turnstile'
@@ -0,0 +1,20 @@
1
+ module Turnstile
2
+ class Sampler
3
+ def extrapolate(n)
4
+ (n * 100.0 / sampling_rate).to_i
5
+ end
6
+
7
+ # this method uses a unique string to integer hashing (object->hash)
8
+ # sampling shifts depending on the day of the month so that sampling
9
+ # does not stick to the same people all the time
10
+ def sample(uid)
11
+ ((uid.hash + Time.now.day) % 100) < sampling_rate
12
+ end
13
+
14
+ private
15
+
16
+ def sampling_rate
17
+ Turnstile.config.sampling_rate
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Turnstile
2
+ class Tracker
3
+ def track(uid, platform = 'unknown', ip = nil)
4
+ adapter.add(uid, platform, ip) if sampler.sample(uid)
5
+ end
6
+
7
+ private
8
+
9
+ def adapter
10
+ @adapter ||= Adapter.new
11
+ end
12
+
13
+ def sampler
14
+ @sampler ||= Sampler.new
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module Turnstile
2
+ VERSION = '2.0.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ stuff hello x-turnstile|desktop|124.5.4.3|AF39945f8f87F more stuff
2
+ stuff hello x-turnstile|iphone|124.3.1.2|AF39945f8f87F more stuff
3
+ stuff hello x-turnstile|desktop|124.5.4.3|AF39945f8f87F more stuff
4
+ stuff hello x-turnstile|desktop|124.5.4.3|AF39945f8f87F more stuff
@@ -0,0 +1,37 @@
1
+ {"method":"GET","path":"/api/v1/users/5462583","format":"json","controller":"Api::V1::UsersController","action":"show","status":200,"duration":17.69,"view":11.92,"db":3.15,"time":"2017-03-22 10:46:17.592 -0700","pid":42045,"user_id":5462583,"platform":"ipad","session_id":"U6Dx4zoASN5KYfh6qLyU","params":{"last_view":"WMagicFeedViewController","client_id":"101","time":"1490204776","auth_token":"U6Dx4zoASN5KYfh6qLyU","format":"json","controller":"api/v1/users","action":"show","id":"5462583","user":{}},"ip_address":"69.61.173.104","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
2
+ called users_with_profile_by_product with per=10
3
+ {"method":"GET","path":"/api/v1/search/suggestions","format":"json","controller":"Api::V1::SearchController","action":"autocomplete","status":200,"duration":33.92,"view":17.07,"db":7.85,"time":"2017-03-22 10:46:17.622 -0700","pid":42021,"user_id":20860276,"platform":"iphone","session_id":"SRj6ePyUU9ey3y7DrFZw","params":{"query":"crop","type":"","last_view":"WProductSearchResultsViewController","client_id":"101","time":"1490204776","auth_token":"SRj6ePyUU9ey3y7DrFZw","format":"json","controller":"api/v1/search","action":"autocomplete","search":{}},"ip_address":"107.152.104.81","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
4
+ {"method":"GET","path":"/api/v1/products/39862579/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":70.26,"view":50.62,"db":15.4,"time":"2017-03-22 10:46:17.606 -0700","pid":42025,"user_id":null,"platform":"android","session_id":null,"params":{"format":"json","controller":"api/v1/products","action":"details","id":"39862579"},"ip_address":"23.235.47.28","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
5
+ {"method":"GET","path":"/api/v1/themes/products/5","format":"json","controller":"Api::V1::ThemesController","action":"products","status":200,"duration":944.52,"view":489.56,"db":195.77,"time":"2017-03-22 10:46:16.746 -0700","pid":42042,"user_id":5445274,"platform":"iphone","session_id":"qRQCRidfy88bHs1MzfYP","params":{"theme_path":"women,dresses,casual","last_view":"theme_Casual","client_id":"101","time":"1490204775","auth_token":"qRQCRidfy88bHs1MzfYP","format":"json","controller":"api/v1/themes","action":"products","page":"5","theme":{}},"ip_address":"68.134.103.85","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
6
+ {"method":"GET","path":"/api/v1/search/products/4","format":"json","controller":"Api::V1::ProductSearchController","action":"products","status":200,"duration":4.21,"view":0.0,"db":0.0,"time":"2017-03-22 10:46:17.693 -0700","pid":42021,"user_id":21086925,"platform":"iphone","session_id":"JKiDpyhSB5jaxwV9tECh","params":{"last_view":"theme_On Sale Now","on_sale":"true","per_page":"60","query":"","preprocess_query":"true","user":"brittnaydickinson","client_id":"101","time":"1490204776","auth_token":"JKiDpyhSB5jaxwV9tECh","format":"json","controller":"api/v1/product_search","action":"products","page":"4","product_search":{}},"ip_address":"168.17.61.221","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
7
+ searching solr for products (grand AND theft AND auto).. (elapsed: 1202.27ms)
8
+ {"method":"GET","path":"/api/v1/users/20447675","format":"json","controller":"Api::V1::UsersController","action":"show","status":200,"duration":23.39,"view":17.63,"db":3.29,"time":"2017-03-22 10:46:17.783 -0700","pid":42042,"user_id":20447675,"platform":"android","session_id":"vZQ5pJiPTLTsg7honwV5","params":{"time":"1490204777","client_id":"android","auth_token":"vZQ5pJiPTLTsg7honwV5","format":"json","controller":"api/v1/users","action":"show","id":"20447675"},"ip_address":"174.218.137.85","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
9
+ {"method":"GET","path":"/api/v1/users/19981112","format":"json","controller":"Api::V1::UsersController","action":"show","status":200,"duration":20.27,"view":14.9,"db":2.53,"time":"2017-03-22 10:46:17.793 -0700","pid":42030,"user_id":19981112,"platform":"iphone","session_id":"yyKeorp4QD98sxN4zLBu","params":{"last_view":"WReviewPhotosViewController","client_id":"101","time":"1490204777","auth_token":"yyKeorp4QD98sxN4zLBu","format":"json","controller":"api/v1/users","action":"show","id":"19981112","user":{}},"ip_address":"73.194.214.138","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
10
+ {"method":"GET","path":"/api/v1/users/4970486/order_surveys/current","format":"json","controller":"Api::V1::OrderSurveysController","action":"current","status":200,"duration":24.9,"view":10.6,"db":6.78,"time":"2017-03-22 10:46:17.841 -0700","pid":42030,"user_id":4970486,"platform":"iphone","session_id":"5z68kWXoCmWrwLidCut1","params":{"survey_version":"2","last_view":"WGuestLandingViewController","client_id":"101","time":"1490204777","auth_token":"5z68kWXoCmWrwLidCut1","format":"json","controller":"api/v1/order_surveys","action":"current","id":"4970486","order_survey":{}},"ip_address":"66.87.112.30","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
11
+ {"method":"GET","path":"/api/v1/saves/4SB8U-1Am9u-4ixC5","format":"json","controller":"Api::V1::SavesController","action":"show","status":200,"duration":49.01,"view":0.3,"db":9.31,"time":"2017-03-22 10:46:17.873 -0700","pid":42042,"user_id":17344742,"platform":"iphone","session_id":"4eKMZJ4nggzvkix29zpS","params":{"last_view":"product","client_id":"101","time":"1490204776","auth_token":"4eKMZJ4nggzvkix29zpS","format":"json","controller":"api/v1/saves","action":"show","id":"4SB8U-1Am9u-4ixC5","save":{}},"ip_address":"70.210.128.241","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
12
+ {"method":"GET","path":"/api/v1/products/trending","format":"json","controller":"Api::V1::TrendingController","action":"show","status":200,"duration":45.76,"view":17.29,"db":2.34,"time":"2017-03-22 10:46:17.878 -0700","pid":42021,"user_id":4970486,"platform":"iphone","session_id":"5z68kWXoCmWrwLidCut1","params":{"last_view":"trending","ignore_price_filters":"true","type":"","product_categories_from_settings":"true","client_id":"101","time":"1490204777","auth_token":"5z68kWXoCmWrwLidCut1","format":"json","controller":"api/v1/trending","action":"show","trending":{}},"ip_address":"66.87.112.30","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
13
+ {"method":"GET","path":"/api/v1/products/26548478/reviews","format":"json","controller":"Api::V1::ReviewsController","action":"product_index","status":200,"duration":21.28,"view":5.36,"db":6.0,"time":"2017-03-22 10:46:17.950 -0700","pid":42021,"user_id":10768109,"platform":"iphone","session_id":"RcT9ekNbhPsqydG4Pv7V","params":{"last_view":"WProductReviewsTableViewController","client_id":"101","time":"1490204776","auth_token":"RcT9ekNbhPsqydG4Pv7V","format":"json","controller":"api/v1/reviews","action":"product_index","product_id":"26548478","review":{}},"ip_address":"12.7.40.147","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
14
+ {"method":"GET","path":"/api/v1/products/40701853/variants/with_availability","format":"json","controller":"Api::V1::ProductsController","action":"variants_with_availability","status":200,"duration":312.66,"view":3.71,"db":26.85,"time":"2017-03-22 10:46:17.700 -0700","pid":42045,"user_id":8554487,"platform":"iphone","session_id":"qVwqQKpoBEtpE5H7TFpd","params":{"last_view":"product","f_type":"sf_195_cents_markup","p_type":"default","client_id":"101","time":"1490204777","auth_token":"qVwqQKpoBEtpE5H7TFpd","format":"json","controller":"api/v1/products","action":"variants_with_availability","id":"40701853","product":{}},"ip_address":"199.79.169.163","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
15
+ called users_with_profile_by_product with per=10
16
+ {"method":"GET","path":"/api/v1/products/50891048/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":76.89,"view":58.04,"db":15.28,"time":"2017-03-22 10:46:18.020 -0700","pid":42021,"user_id":null,"platform":"iphone","session_id":null,"params":{"f_type":"sf_180_cents_markup","p_type":"","format":"json","controller":"api/v1/products","action":"details","id":"50891048","product":{}},"ip_address":"23.235.47.40","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
17
+ {"method":"GET","path":"/search","format":"html","controller":"SearchController","action":"products","status":200,"duration":1595.73,"view":346.95,"db":50.27,"time":"2017-03-22 10:46:16.513 -0700","pid":42077,"user_id":null,"platform":"desktop","session_id":"90bba1d374001aedfe5b31525a528513","params":{"ref":"gsl","query":"Grand Theft Auto","page":"2","controller":"search","action":"products"},"ip_address":"162.223.13.23","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"6LZrqw6xsO3nEiyheu340L7ObsGeCFmM11BILUFqljQ=","verified_request":true}
18
+ {"method":"HEAD","path":"/shop/custom-timberland-boots-etsy","format":"html","controller":"SeoPhrasesController","action":"show","status":200,"duration":1167.48,"view":391.63,"db":389.24,"time":"2017-03-22 10:46:16.966 -0700","pid":42079,"user_id":null,"platform":"desktop","session_id":"c00000b340017143f8502d0a2520274e","params":{"wnl_page_type":"Shop Page","wnl_page_version":"1.0","controller":"seo_phrases","action":"show","slug":"custom-timberland-boots-etsy"},"ip_address":"52.90.73.229","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"4x1n4QllLThOYpXmR8bJgb8k+akwy1tBznIJWAttsLs=","verified_request":true}
19
+ {"method":"GET","path":"/api/v1/users/me/activity_feed/unified/2","format":"json","controller":"Api::V1::MagicFeedController","action":"unified","status":200,"duration":168.39,"view":70.15,"db":41.48,"time":"2017-03-22 10:46:17.973 -0700","pid":42042,"user_id":19719275,"platform":"iphone","session_id":"ywEoKieAZSvU7yoEbeyV","params":{"type":"no_affiliate_in_mf","last_view":"WMagicFeedViewController","client_id":"101","time":"1490204777","auth_token":"ywEoKieAZSvU7yoEbeyV","format":"json","controller":"api/v1/magic_feed","action":"unified","page":"2","magic_feed":{}},"ip_address":"69.80.178.31","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
20
+ Can't verify CSRF token authenticity
21
+ called users_with_profile_by_product with per=10
22
+ {"method":"GET","path":"/api/v1/saves/48WAQ-FpJA-4hvZ5/comments","format":"json","controller":"Api::V1::CommentsController","action":"index","status":200,"duration":7.9,"view":0.12,"db":2.36,"time":"2017-03-22 10:46:18.272 -0700","pid":42042,"user_id":null,"platform":"iphone","session_id":null,"params":{"order":"least_recent_first","format":"json","type":"save","controller":"api/v1/comments","action":"index","save_id":"48WAQ-FpJA-4hvZ5","comment":{}},"ip_address":"23.235.47.22","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
23
+ {"method":"GET","path":"/api/v1/saves/aTqO-8IVC-ew1O","format":"json","controller":"Api::V1::SavesController","action":"show","status":200,"duration":78.78,"view":0.38,"db":11.27,"time":"2017-03-22 10:46:18.229 -0700","pid":42079,"user_id":1977750,"platform":"iphone","session_id":"kHg6giEpAAQykW8uM6nf","params":{"last_view":"product","client_id":"101","time":"1490204777","auth_token":"kHg6giEpAAQykW8uM6nf","format":"json","controller":"api/v1/saves","action":"show","id":"aTqO-8IVC-ew1O","save":{}},"ip_address":"70.209.144.195","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
24
+ {"method":"GET","path":"/api/v1/products/40479095/comments","format":"json","controller":"Api::V1::CommentsController","action":"index","status":200,"duration":87.47,"view":0.16,"db":20.6,"time":"2017-03-22 10:46:18.298 -0700","pid":42088,"user_id":null,"platform":"iphone","session_id":null,"params":{"paged":"1","order":"least_recent_first","format":"json","type":"product","controller":"api/v1/comments","action":"index","product_id":"40479095","comment":{}},"ip_address":"23.235.47.40","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
25
+ {"method":"GET","path":"/api/v1/products/18531328/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":177.23,"view":153.44,"db":20.25,"time":"2017-03-22 10:46:18.223 -0700","pid":42045,"user_id":null,"platform":"iphone","session_id":null,"params":{"f_type":"sf_195_cents_markup","p_type":"default","format":"json","controller":"api/v1/products","action":"details","id":"18531328","product":{}},"ip_address":"23.235.47.51","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
26
+ {"method":"GET","path":"/api/v1/suggestions/products/8694532","format":"json","controller":"Api::V1::SuggestionsController","action":"products","status":200,"duration":451.62,"view":0.18,"db":153.67,"time":"2017-03-22 10:46:17.975 -0700","pid":42026,"user_id":null,"platform":"iphone","session_id":null,"params":{"type":"","format":"json","controller":"api/v1/suggestions","action":"products","product_id":"8694532","suggestion":{}},"ip_address":"23.235.47.44","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
27
+ {"method":"GET","path":"/api/v1/search/suggestions","format":"json","controller":"Api::V1::SearchController","action":"autocomplete","status":200,"duration":34.19,"view":17.4,"db":5.94,"time":"2017-03-22 10:46:18.400 -0700","pid":42079,"user_id":20860276,"platform":"iphone","session_id":"SRj6ePyUU9ey3y7DrFZw","params":{"query":"crop ","type":"","last_view":"WProductSearchResultsViewController","client_id":"101","time":"1490204777","auth_token":"SRj6ePyUU9ey3y7DrFZw","format":"json","controller":"api/v1/search","action":"autocomplete","search":{}},"ip_address":"107.152.104.81","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
28
+ called users_with_profile_by_product with per=10
29
+ {"method":"POST","path":"/api/v1/orders","format":"json","controller":"Api::V1::OrdersController","action":"new","status":200,"duration":343.03,"view":66.05,"db":142.68,"time":"2017-03-22 10:46:18.170 -0700","pid":42077,"user_id":9675208,"platform":"iphone","session_id":"9m5w4vTrfj7FVie9EMyN","params":{"product_id":"53487642","f_type":"sf_195_cents_markup","merge_tax_and_service_fee":"true","p_type":"default","last_view":"product","client_id":"101","time":"1490204776","auth_token":"9m5w4vTrfj7FVie9EMyN","format":"json","controller":"api/v1/orders","action":"new","order":{}},"ip_address":"172.56.29.65","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
30
+ {"method":"GET","path":"/api/v1/products/42913240/details","format":"json","controller":"Api::V1::ProductsController","action":"details","status":200,"duration":70.92,"view":48.06,"db":19.16,"time":"2017-03-22 10:46:18.457 -0700","pid":42026,"user_id":null,"platform":"iphone","session_id":null,"params":{"f_type":"sf_195_cents_markup","p_type":"fbw115","format":"json","controller":"api/v1/products","action":"details","id":"42913240","product":{}},"ip_address":"23.235.47.43","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
31
+ {"method":"GET","path":"/api/v1/suggestions/products/39862579","format":"json","controller":"Api::V1::SuggestionsController","action":"products","status":200,"duration":430.93,"view":0.36,"db":75.16,"time":"2017-03-22 10:46:18.100 -0700","pid":42009,"user_id":null,"platform":"android","session_id":null,"params":{"type":"buyable_and_affiliate","format":"json","controller":"api/v1/suggestions","action":"products","product_id":"39862579"},"ip_address":"23.235.47.49","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
32
+ {"method":"GET","path":"/api/v1/users/678238/collections","format":"json","controller":"Api::V1::UsersController","action":"collections","status":200,"duration":12.89,"view":0.14,"db":4.59,"time":"2017-03-22 10:46:18.608 -0700","pid":42026,"user_id":678238,"platform":"iphone","session_id":"L4dgADorpsmQUWFv5vJ7","params":{"last_view":"WMagicFeedViewController","client_id":"101","time":"1490204777","auth_token":"L4dgADorpsmQUWFv5vJ7","format":"json","controller":"api/v1/users","action":"collections","id":"678238","user":{}},"ip_address":"132.189.82.11","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
33
+ {"method":"GET","path":"/api/v1/products/34552155/variants/with_availability","format":"json","controller":"Api::V1::ProductsController","action":"variants_with_availability","status":200,"duration":77.38,"view":0.67,"db":17.95,"time":"2017-03-22 10:46:18.595 -0700","pid":42009,"user_id":10151188,"platform":"android","session_id":"uK8wwYNZjqXnoZz1bpGm","params":{"time":"1490204777","client_id":"android","auth_token":"uK8wwYNZjqXnoZz1bpGm","format":"json","controller":"api/v1/products","action":"variants_with_availability","id":"34552155"},"ip_address":"172.58.67.103","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
34
+ {"method":"GET","path":"/api/v1/users/5754901/collections","format":"json","controller":"Api::V1::UsersController","action":"collections","status":200,"duration":7.72,"view":0.12,"db":1.02,"time":"2017-03-22 10:46:18.668 -0700","pid":42088,"user_id":5754901,"platform":"iphone","session_id":"zqsActyuTd8zXpBo92ct","params":{"last_view":"trending","client_id":"101","time":"1490204777","auth_token":"zqsActyuTd8zXpBo92ct","format":"json","controller":"api/v1/users","action":"collections","id":"5754901","user":{}},"ip_address":"70.210.64.69","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":null,"verified_request":null}
35
+ {"method":"POST","path":"/int/admin/stores/591600","format":"html","controller":"Admin::StoresController","action":"update","status":302,"duration":44.47,"view":0.0,"db":11.61,"location":"https://wanelo.co/int/admin/stores/591600","time":"2017-03-22 10:46:06.609 -0700","pid":75556,"user_id":14092896,"platform":"desktop","session_id":"2730608f1d862d6250f541b19ce8ffd3","params":{"_method":"put","authenticity_token":"t3A2nHFu5hyKmM66NPdEBUKBU4ePPlFGr0ufr64Qpzc=","store":{"category_id_with_event":"5"},"action":"update","controller":"admin/stores","id":"591600"},"ip_address":"182.255.42.49","hostname":null,"xhr":false,"authenticity_token":"t3A2nHFu5hyKmM66NPdEBUKBU4ePPlFGr0ufr64Qpzc=","authenticity_token_header":null,"expected_auth_token":"t3A2nHFu5hyKmM66NPdEBUKBU4ePPlFGr0ufr64Qpzc=","verified_request":true}
36
+ {"method":"GET","path":"/int/admin/stores/536402","format":"html","controller":"Admin::StoresController","action":"show","status":200,"duration":696.01,"view":267.24,"db":229.64,"time":"2017-03-22 10:46:05.977 -0700","pid":75568,"user_id":14092901,"platform":"desktop","session_id":"777dbb41f8d29008b1555630f1fb31a3","params":{"action":"show","controller":"admin/stores","id":"536402"},"ip_address":"103.196.139.175","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"IV7BLkptllMtK+FAerenwT4bjFGaLymGD4jei9znUGw=","verified_request":true}
37
+ {"method":"GET","path":"/store/joyworkshoppe","format":"html","controller":"Legacy::StoresController","action":"show","status":200,"duration":469.7,"view":434.78,"db":16.0,"time":"2017-03-22 10:46:17.090 -0700","pid":42025,"user_id":null,"platform":"mobile_web","session_id":"5058494231f66532c08371587ed4eeb7","params":{"wnl_page_type":"Wanelo.com Store Page","wnl_page_version":"1.0","controller":"legacy/stores","action":"show","id":"joyworkshoppe"},"ip_address":"75.155.232.189","hostname":null,"xhr":false,"authenticity_token":null,"authenticity_token_header":null,"expected_auth_token":"Nf9dMhJlWzFHkzUouHnSLm1Cd+1EaSesoa75HhkJRkw=","verified_request":true}
@@ -0,0 +1,24 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
+
10
+ require 'rubygems'
11
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
12
+ require 'simplecov'
13
+
14
+ SimpleCov.start
15
+
16
+ require 'turnstile'
17
+ require 'rspec/its'
18
+
19
+ RSpec.configure do |config|
20
+ config.order = 'random'
21
+ config.before :each do
22
+ Turnstile::Adapter.new.redis.flushdb
23
+ end
24
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnstile::Adapter do
4
+
5
+ subject { Turnstile::Adapter.new }
6
+
7
+ let(:redis) { subject.send(:redis) }
8
+
9
+ let(:uid) { 1238438 }
10
+ let(:other_uid) { 1238439 }
11
+ let(:another_uid) { 1238440 }
12
+
13
+ let(:ip) { '1.2.3.4' }
14
+ let(:another_ip) { '4.3.2.1' }
15
+
16
+ let(:platform) { :ios }
17
+ let(:another_platform) { :android }
18
+
19
+ describe '#add' do
20
+ it 'calls redis with the correct params' do
21
+ key = "t:#{uid}:#{platform}:#{ip}"
22
+ expect(redis).to receive(:setex).once.with(key, Turnstile.config.activity_interval, 1)
23
+ subject.add(uid, platform, ip)
24
+ end
25
+ end
26
+
27
+ describe '#fetch' do
28
+ let(:sort_lambda) { ->(a, b) { a[:uid] <=> b[:uid] } }
29
+ let(:expected_hash) do
30
+ [
31
+ { uid: uid.to_s, platform: platform.to_s, ip: ip },
32
+ { uid: other_uid.to_s, platform: platform.to_s, ip: ip },
33
+ { uid: another_uid.to_s, platform: another_platform.to_s, ip: another_ip },
34
+ ]
35
+ end
36
+
37
+ before do
38
+ subject.add(uid, platform, ip)
39
+ subject.add(other_uid, platform, ip)
40
+ subject.add(another_uid, another_platform, another_ip)
41
+ end
42
+
43
+ it 'pulls the platform specific stats from redis' do
44
+ expect(subject.fetch.sort(&sort_lambda)).to eq(expected_hash.sort(&sort_lambda))
45
+ end
46
+ end
47
+
48
+ describe '#aggregate' do
49
+ let(:expected_hash) do
50
+ {
51
+ 'android' => 3,
52
+ 'ios' => 2,
53
+ 'total' => 5
54
+ }
55
+ end
56
+
57
+ before do
58
+ subject.add(123, :android, ip)
59
+ subject.add(124, :android, ip)
60
+ subject.add(125, :android, ip)
61
+
62
+ subject.add(200, :ios, ip)
63
+ subject.add(201, :ios, ip)
64
+ end
65
+
66
+ it 'should calculated proper aggregation' do
67
+ expect(subject.aggregate).to eql expected_hash
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+ require 'file/tail'
3
+ require 'timeout'
4
+ require 'thread'
5
+ require 'tempfile'
6
+
7
+ require 'turnstile/collector/log_reader'
8
+
9
+ describe Turnstile::Collector::LogReader do
10
+ include Timeout
11
+
12
+ def consume_file(reader, read_timeout)
13
+ hash = {}
14
+ counter = 0
15
+
16
+ run_reader(read_timeout) do
17
+ reader.read do |token|
18
+ counter += 1
19
+ hash[token] = 1
20
+ end
21
+ end
22
+ return counter, hash
23
+ end
24
+
25
+ def run_reader(read_timeout, &block)
26
+ t_reader = Thread.new do
27
+ begin
28
+ timeout(read_timeout) do
29
+ block.call
30
+ end
31
+ rescue Timeout::Error
32
+ end
33
+ end
34
+ t_reader.join
35
+ end
36
+
37
+ let(:queue) { Queue.new }
38
+ let(:read_timeout) { 0.1 }
39
+ let(:consume_file_result) { consume_file(reader, read_timeout) }
40
+ let(:counter) { consume_file_result.first }
41
+ let(:hash) { consume_file_result.last }
42
+
43
+ before { reader.file.backward(1000) }
44
+
45
+ context 'json log file' do
46
+ let(:file) { 'spec/fixtures/sample-production.log.json' }
47
+ let(:reader) { Turnstile::Collector::LogReader.json_formatted(file, queue) }
48
+
49
+ let(:expected_uniques) { 28 }
50
+ let(:expected_total) { 31 }
51
+ let(:expected_key) { 'ipad:69.61.173.104:5462583' }
52
+
53
+ context '#read' do
54
+ it 'should be able to read and parse IPs from a static file' do
55
+ expect(counter).to eql(expected_total)
56
+ expect(hash.keys.size).to eql(expected_uniques)
57
+ expect(hash.keys).to include(expected_key)
58
+ end
59
+ end
60
+
61
+ context '#process!' do
62
+ it 'should read values into the queue' do
63
+ run_reader(read_timeout) { reader.process! }
64
+ expect(queue.size).to eql(31)
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'pipe delimited file' do
70
+ let(:file) { 'spec/fixtures/sample-production.log' }
71
+ let(:reader) { Turnstile::Collector::LogReader.pipe_delimited(file, queue) }
72
+
73
+ let(:log_reader) { Turnstile::Collector::LogReader }
74
+
75
+ let(:expected_uniques) { 2 }
76
+ let(:expected_total) { 4 }
77
+ let(:expected_key) { 'desktop:124.5.4.3:AF39945f8f87F' }
78
+
79
+ context 'matcher' do
80
+ subject(:matcher) { log_reader.delimited_matcher }
81
+
82
+ its(:regexp) { should_not be_nil }
83
+
84
+ its(:extractor) { should_not be_nil }
85
+ its(:extractor) { should be_kind_of(Proc) }
86
+
87
+ it 'should match lines in the file' do
88
+ File.open(file).each do |line|
89
+ expect(line).to match(matcher.regexp)
90
+ end
91
+ end
92
+ it 'should extract the token from file' do
93
+ File.open(file).each do |line|
94
+ expect(matcher.token_from(line)).to_not be_nil
95
+ end
96
+ end
97
+ end
98
+
99
+ context '#read' do
100
+ it 'should be load all matching rows' do
101
+ expect(counter).to eql(expected_total)
102
+ expect(hash.keys.size).to eql(expected_uniques)
103
+ expect(hash.keys).to include(expected_key)
104
+ end
105
+ end
106
+
107
+ context '#process!' do
108
+ it 'should read values into the queue' do
109
+ run_reader(read_timeout) { reader.process! }
110
+ expect(queue.size).to eql(expected_total)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnstile::Configuration do
4
+
5
+ subject(:config) { Turnstile::Configuration.new }
6
+
7
+ let(:spec_ip) { '128.23.12.8' }
8
+ let(:spec_port) { '2134' }
9
+ let(:spec_db) { '13' }
10
+ let(:spec_timeout) { 0.087 }
11
+ let(:spec_activity_interval) { 30 }
12
+ let(:spec_sampling_rate) { 10 }
13
+
14
+ context 'using redis sub-config method missing' do
15
+ before do
16
+ config.configure do |c|
17
+ c.redis.configure do |r|
18
+ r.host = spec_ip
19
+ r.port = spec_port
20
+ r.db = spec_db
21
+ r.timeout = spec_timeout
22
+ end
23
+ c.activity_interval = spec_activity_interval
24
+ c.sampling_rate = spec_sampling_rate
25
+ end
26
+ end
27
+
28
+ context 'main config' do
29
+ its(:activity_interval) { should eq spec_activity_interval }
30
+ its(:sampling_rate) { should eq spec_sampling_rate }
31
+ end
32
+
33
+ context 'redis sub-config' do
34
+ subject(:redis_config) { config.redis }
35
+ its(:host) { should eq spec_ip }
36
+ its(:port) { should eq spec_port.to_i }
37
+ its(:db) { should eq spec_db.to_i }
38
+ its(:timeout) { should eq spec_timeout.to_f }
39
+ end
40
+ end
41
+
42
+ context 'using redis_<property> method missing' do
43
+ before do
44
+ config.configure do |c|
45
+ c.redis_host = spec_ip
46
+ c.redis_port = spec_port
47
+ c.redis_db = spec_db
48
+ c.redis_timeout = spec_timeout
49
+ c.activity_interval = spec_activity_interval
50
+ c.sampling_rate = spec_sampling_rate
51
+ end
52
+ end
53
+
54
+ its(:redis_host) { should eq spec_ip }
55
+ its(:redis_port) { should eq spec_port.to_i }
56
+ its(:redis_db) { should eq spec_db.to_i }
57
+ its(:redis_timeout) { should eq spec_timeout.to_f }
58
+ its(:activity_interval) { should eq spec_activity_interval }
59
+ its(:sampling_rate) { should eq spec_sampling_rate }
60
+ end
61
+
62
+ context 'without explicit assignment' do
63
+ let(:spec_ip) { '127.0.0.1' }
64
+ let(:spec_port) { 6379 }
65
+ let(:spec_db) { 1 }
66
+ let(:spec_timeout) { 0.05 }
67
+ let(:spec_activity_interval) { 60 }
68
+ let(:spec_sampling_rate) { 100 }
69
+
70
+ its(:redis_host) { should eq spec_ip }
71
+ its(:redis_port) { should eq spec_port }
72
+ its(:redis_db) { should eq spec_db }
73
+ its(:redis_timeout) { should eq spec_timeout }
74
+ its(:activity_interval) { should eq spec_activity_interval }
75
+ its(:sampling_rate) { should eq spec_sampling_rate }
76
+ end
77
+
78
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Turnstile::Nad' do
4
+
5
+ subject { Turnstile::Nad.new }
6
+
7
+ describe '#data' do
8
+ context 'have some data' do
9
+ let(:aggregate) { {
10
+ 'android' => 3,
11
+ 'ios' => 2,
12
+ 'total' => 5
13
+ }
14
+ }
15
+
16
+ let(:expected_string) {
17
+ <<-EOF
18
+ turnstile:android#{"\t"}n#{"\t"}3
19
+ turnstile:ios#{"\t"}n#{"\t"}2
20
+ turnstile:total#{"\t"}n#{"\t"}5
21
+ EOF
22
+ }
23
+
24
+ it "return data in NAD tab dilimited format" do
25
+ expect(subject).to receive(:aggregate).once.and_return(aggregate)
26
+ expect(subject.data).to eql(expected_string)
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Turnstile::Observer do
4
+
5
+ subject { Turnstile::Observer.new }
6
+
7
+ let(:adapter) { subject.send(:adapter) }
8
+
9
+ let(:uid) { 1238438 }
10
+ let(:platform) { :ios }
11
+ let(:ip) { '1.2.3.4' }
12
+
13
+ let(:sample_data) { [{uid: uid, platform: platform, ip: ip}] }
14
+
15
+ let(:expected_stats) do
16
+ {
17
+ stats: {
18
+ total: 1,
19
+ platforms: {
20
+ ios: 1
21
+ }
22
+ },
23
+ users: sample_data
24
+ }
25
+ end
26
+
27
+ let(:extrapolated_stats) do
28
+ {
29
+ stats: {
30
+ total: 20,
31
+ platforms: {
32
+ ios: 20
33
+ }
34
+ },
35
+ users: sample_data
36
+ }
37
+ end
38
+
39
+ describe '#stats' do
40
+ context 'when there are users' do
41
+ before do
42
+ expect(adapter).to receive(:fetch).once.and_return(sample_data)
43
+ end
44
+
45
+ it 'fetches data from adapter and aggregates it' do
46
+ expect(subject.stats).to eql(expected_stats)
47
+ end
48
+
49
+ it 'extrapolates numbers correctly' do
50
+ allow(Turnstile.config).to receive(:sampling_rate).and_return(5)
51
+ expect(subject.stats).to eql(extrapolated_stats)
52
+ end
53
+ end
54
+
55
+ context 'when there are no users' do
56
+ before do
57
+ expect(adapter).to receive(:fetch).once.and_return([])
58
+ end
59
+
60
+ it 'returns 0 for total' do
61
+ expect(subject.stats[:stats][:total]).to eql 0
62
+ end
63
+ end
64
+ end
65
+ end