appsignal 4.2.0 → 4.5.17

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +443 -0
  3. data/README.md +0 -3
  4. data/Rakefile +1 -1
  5. data/appsignal.gemspec +2 -1
  6. data/build_matrix.yml +33 -0
  7. data/ext/agent.rb +27 -27
  8. data/ext/appsignal_extension.c +90 -73
  9. data/ext/base.rb +3 -1
  10. data/lib/appsignal/check_in/event.rb +55 -0
  11. data/lib/appsignal/check_in/scheduler.rb +8 -2
  12. data/lib/appsignal/check_in.rb +9 -8
  13. data/lib/appsignal/config.rb +36 -15
  14. data/lib/appsignal/custom_marker.rb +72 -0
  15. data/lib/appsignal/environment.rb +1 -0
  16. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +4 -6
  17. data/lib/appsignal/event_formatter/view_component/render_formatter.rb +4 -6
  18. data/lib/appsignal/helpers/instrumentation.rb +5 -0
  19. data/lib/appsignal/hooks/active_job.rb +25 -5
  20. data/lib/appsignal/hooks/at_exit.rb +18 -4
  21. data/lib/appsignal/hooks/ownership.rb +44 -0
  22. data/lib/appsignal/hooks.rb +1 -0
  23. data/lib/appsignal/integrations/capistrano/appsignal.cap +4 -8
  24. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +8 -11
  25. data/lib/appsignal/integrations/http.rb +2 -1
  26. data/lib/appsignal/integrations/ownership.rb +51 -0
  27. data/lib/appsignal/integrations/rake.rb +14 -2
  28. data/lib/appsignal/integrations/sidekiq.rb +14 -3
  29. data/lib/appsignal/internal_errors.rb +19 -0
  30. data/lib/appsignal/logger.rb +121 -69
  31. data/lib/appsignal/marker.rb +1 -1
  32. data/lib/appsignal/probes/sidekiq.rb +5 -1
  33. data/lib/appsignal/rack/body_wrapper.rb +1 -1
  34. data/lib/appsignal/rack/event_handler.rb +7 -5
  35. data/lib/appsignal/transaction.rb +91 -13
  36. data/lib/appsignal/version.rb +1 -1
  37. data/lib/appsignal.rb +82 -11
  38. data/resources/cacert.pem +164 -87
  39. metadata +8 -4
@@ -15,6 +15,30 @@ static inline VALUE make_ruby_string(appsignal_string_t string) {
15
15
  return str;
16
16
  }
17
17
 
18
+ const rb_data_type_t transaction_data_type = {
19
+ .wrap_struct_name = "Appsignal::Extension::Transaction",
20
+ .function = {
21
+ .dfree = appsignal_free_transaction,
22
+ },
23
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
24
+ };
25
+
26
+ const rb_data_type_t data_data_type = {
27
+ .wrap_struct_name = "Appsignal::Extension::Data",
28
+ .function = {
29
+ .dfree = appsignal_free_data,
30
+ },
31
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
32
+ };
33
+
34
+ const rb_data_type_t span_data_type = {
35
+ .wrap_struct_name = "Appsignal::Extension::Span",
36
+ .function = {
37
+ .dfree = appsignal_free_span,
38
+ },
39
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
40
+ };
41
+
18
42
  VALUE Appsignal;
19
43
  VALUE Extension;
20
44
  VALUE Transaction;
@@ -64,7 +88,7 @@ static VALUE start_transaction(VALUE self, VALUE transaction_id, VALUE namespace
64
88
  );
65
89
 
66
90
  if (transaction) {
67
- return Data_Wrap_Struct(Transaction, NULL, appsignal_free_transaction, transaction);
91
+ return TypedData_Wrap_Struct(Transaction, &transaction_data_type, transaction);
68
92
  } else {
69
93
  return Qnil;
70
94
  }
@@ -75,7 +99,7 @@ static VALUE start_event(VALUE self, VALUE gc_duration_ms) {
75
99
 
76
100
  Check_Type(gc_duration_ms, T_FIXNUM);
77
101
 
78
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
102
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
79
103
 
80
104
  appsignal_start_event(transaction, NUM2LONG(gc_duration_ms));
81
105
 
@@ -91,7 +115,7 @@ static VALUE finish_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE
91
115
  Check_Type(title, T_STRING);
92
116
  Check_Type(body_format, T_FIXNUM);
93
117
 
94
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
118
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
95
119
 
96
120
  body_type = TYPE(body);
97
121
  if (body_type == T_STRING) {
@@ -103,8 +127,8 @@ static VALUE finish_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE
103
127
  FIX2INT(body_format),
104
128
  FIX2LONG(gc_duration_ms)
105
129
  );
106
- } else if (body_type == RUBY_T_DATA) {
107
- Data_Get_Struct(body, appsignal_data_t, body_data);
130
+ } else if (body_type == T_DATA) {
131
+ TypedData_Get_Struct(body, appsignal_data_t, &data_data_type, body_data);
108
132
  appsignal_finish_event_data(
109
133
  transaction,
110
134
  make_appsignal_string(name),
@@ -134,7 +158,7 @@ static VALUE record_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE
134
158
  }
135
159
  Check_Type(body_format, T_FIXNUM);
136
160
 
137
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
161
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
138
162
 
139
163
  body_type = TYPE(body);
140
164
  if (body_type == T_STRING) {
@@ -147,8 +171,8 @@ static VALUE record_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE
147
171
  NUM2LONG(duration),
148
172
  NUM2LONG(gc_duration_ms)
149
173
  );
150
- } else if (body_type == RUBY_T_DATA) {
151
- Data_Get_Struct(body, appsignal_data_t, body_data);
174
+ } else if (body_type == T_DATA) {
175
+ TypedData_Get_Struct(body, appsignal_data_t, &data_data_type, body_data);
152
176
  appsignal_record_event_data(
153
177
  transaction,
154
178
  make_appsignal_string(name),
@@ -171,10 +195,10 @@ static VALUE set_transaction_error(VALUE self, VALUE name, VALUE message, VALUE
171
195
 
172
196
  Check_Type(name, T_STRING);
173
197
  Check_Type(message, T_STRING);
174
- Check_Type(backtrace, RUBY_T_DATA);
175
198
 
176
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
177
- Data_Get_Struct(backtrace, appsignal_data_t, backtrace_data);
199
+ backtrace_data = rb_check_typeddata(backtrace, &data_data_type);
200
+
201
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
178
202
 
179
203
  appsignal_set_transaction_error(
180
204
  transaction,
@@ -190,10 +214,10 @@ static VALUE set_transaction_sample_data(VALUE self, VALUE key, VALUE payload) {
190
214
  appsignal_data_t* payload_data;
191
215
 
192
216
  Check_Type(key, T_STRING);
193
- Check_Type(payload, RUBY_T_DATA);
194
217
 
195
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
196
- Data_Get_Struct(payload, appsignal_data_t, payload_data);
218
+ payload_data = rb_check_typeddata(payload, &data_data_type);
219
+
220
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
197
221
 
198
222
  appsignal_set_transaction_sample_data(
199
223
  transaction,
@@ -207,7 +231,7 @@ static VALUE set_transaction_action(VALUE self, VALUE action) {
207
231
  appsignal_transaction_t* transaction;
208
232
 
209
233
  Check_Type(action, T_STRING);
210
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
234
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
211
235
 
212
236
  appsignal_set_transaction_action(
213
237
  transaction,
@@ -220,7 +244,7 @@ static VALUE set_transaction_namespace(VALUE self, VALUE namespace) {
220
244
  appsignal_transaction_t* transaction;
221
245
 
222
246
  Check_Type(namespace, T_STRING);
223
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
247
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
224
248
 
225
249
  appsignal_set_transaction_namespace(
226
250
  transaction,
@@ -238,7 +262,7 @@ static VALUE set_transaction_queue_start(VALUE self, VALUE queue_start) {
238
262
  rb_raise(rb_eTypeError, "queue_start should be an Integer");
239
263
  }
240
264
 
241
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
265
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
242
266
 
243
267
  appsignal_set_transaction_queue_start(
244
268
  transaction,
@@ -252,7 +276,7 @@ static VALUE set_transaction_metadata(VALUE self, VALUE key, VALUE value) {
252
276
 
253
277
  Check_Type(key, T_STRING);
254
278
  Check_Type(value, T_STRING);
255
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
279
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
256
280
 
257
281
  appsignal_set_transaction_metadata(
258
282
  transaction,
@@ -267,7 +291,7 @@ static VALUE finish_transaction(VALUE self, VALUE gc_duration_ms) {
267
291
  int sample;
268
292
 
269
293
  Check_Type(gc_duration_ms, T_FIXNUM);
270
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
294
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
271
295
 
272
296
  sample = appsignal_finish_transaction(transaction, NUM2LONG(gc_duration_ms));
273
297
  return sample == 1 ? Qtrue : Qfalse;
@@ -278,7 +302,7 @@ static VALUE duplicate_transaction(VALUE self, VALUE new_transaction_id) {
278
302
  appsignal_transaction_t* duplicate_transaction;
279
303
 
280
304
  Check_Type(new_transaction_id, T_STRING);
281
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
305
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
282
306
 
283
307
  duplicate_transaction = appsignal_duplicate_transaction(
284
308
  transaction,
@@ -286,10 +310,9 @@ static VALUE duplicate_transaction(VALUE self, VALUE new_transaction_id) {
286
310
  );
287
311
 
288
312
  if (duplicate_transaction) {
289
- return Data_Wrap_Struct(
313
+ return TypedData_Wrap_Struct(
290
314
  Transaction,
291
- NULL,
292
- appsignal_free_transaction,
315
+ &transaction_data_type,
293
316
  duplicate_transaction
294
317
  );
295
318
  } else {
@@ -300,7 +323,7 @@ static VALUE duplicate_transaction(VALUE self, VALUE new_transaction_id) {
300
323
  static VALUE complete_transaction(VALUE self) {
301
324
  appsignal_transaction_t* transaction;
302
325
 
303
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
326
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
304
327
 
305
328
  appsignal_complete_transaction(transaction);
306
329
  return Qnil;
@@ -310,7 +333,7 @@ static VALUE transaction_to_json(VALUE self) {
310
333
  appsignal_transaction_t* transaction;
311
334
  appsignal_string_t json;
312
335
 
313
- Data_Get_Struct(self, appsignal_transaction_t, transaction);
336
+ TypedData_Get_Struct(self, appsignal_transaction_t, &transaction_data_type, transaction);
314
337
 
315
338
  json = appsignal_transaction_to_json(transaction);
316
339
 
@@ -327,7 +350,7 @@ static VALUE data_map_new(VALUE self) {
327
350
  data = appsignal_data_map_new();
328
351
 
329
352
  if (data) {
330
- return Data_Wrap_Struct(Data, NULL, appsignal_free_data, data);
353
+ return TypedData_Wrap_Struct(Data, &data_data_type, data);
331
354
  } else {
332
355
  return Qnil;
333
356
  }
@@ -339,7 +362,7 @@ static VALUE data_array_new(VALUE self) {
339
362
  data = appsignal_data_array_new();
340
363
 
341
364
  if (data) {
342
- return Data_Wrap_Struct(Data, NULL, appsignal_free_data, data);
365
+ return TypedData_Wrap_Struct(Data, &data_data_type, data);
343
366
  } else {
344
367
  return Qnil;
345
368
  }
@@ -351,7 +374,7 @@ static VALUE data_set_string(VALUE self, VALUE key, VALUE value) {
351
374
  Check_Type(key, T_STRING);
352
375
  Check_Type(value, T_STRING);
353
376
 
354
- Data_Get_Struct(self, appsignal_data_t, data);
377
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
355
378
 
356
379
  appsignal_data_map_set_string(
357
380
  data,
@@ -371,7 +394,7 @@ static VALUE data_set_integer(VALUE self, VALUE key, VALUE value) {
371
394
  rb_raise(rb_eTypeError, "wrong argument type %s (expected Integer)", rb_obj_classname(value));
372
395
  }
373
396
 
374
- Data_Get_Struct(self, appsignal_data_t, data);
397
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
375
398
 
376
399
  appsignal_data_map_set_integer(
377
400
  data,
@@ -388,7 +411,7 @@ static VALUE data_set_float(VALUE self, VALUE key, VALUE value) {
388
411
  Check_Type(key, T_STRING);
389
412
  Check_Type(value, T_FLOAT);
390
413
 
391
- Data_Get_Struct(self, appsignal_data_t, data);
414
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
392
415
 
393
416
  appsignal_data_map_set_float(
394
417
  data,
@@ -404,7 +427,7 @@ static VALUE data_set_boolean(VALUE self, VALUE key, VALUE value) {
404
427
 
405
428
  Check_Type(key, T_STRING);
406
429
 
407
- Data_Get_Struct(self, appsignal_data_t, data);
430
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
408
431
 
409
432
  appsignal_data_map_set_boolean(
410
433
  data,
@@ -420,7 +443,7 @@ static VALUE data_set_nil(VALUE self, VALUE key) {
420
443
 
421
444
  Check_Type(key, T_STRING);
422
445
 
423
- Data_Get_Struct(self, appsignal_data_t, data);
446
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
424
447
 
425
448
  appsignal_data_map_set_null(
426
449
  data,
@@ -435,10 +458,9 @@ static VALUE data_set_data(VALUE self, VALUE key, VALUE value) {
435
458
  appsignal_data_t* value_data;
436
459
 
437
460
  Check_Type(key, T_STRING);
438
- Check_Type(value, RUBY_T_DATA);
461
+ value_data = rb_check_typeddata(value, &data_data_type);
439
462
 
440
- Data_Get_Struct(self, appsignal_data_t, data);
441
- Data_Get_Struct(value, appsignal_data_t, value_data);
463
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
442
464
 
443
465
  appsignal_data_map_set_data(
444
466
  data,
@@ -454,7 +476,7 @@ static VALUE data_append_string(VALUE self, VALUE value) {
454
476
 
455
477
  Check_Type(value, T_STRING);
456
478
 
457
- Data_Get_Struct(self, appsignal_data_t, data);
479
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
458
480
 
459
481
  appsignal_data_array_append_string(
460
482
  data,
@@ -472,7 +494,7 @@ static VALUE data_append_integer(VALUE self, VALUE value) {
472
494
  rb_raise(rb_eTypeError, "wrong argument type %s (expected Integer)", rb_obj_classname(value));
473
495
  }
474
496
 
475
- Data_Get_Struct(self, appsignal_data_t, data);
497
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
476
498
 
477
499
  appsignal_data_array_append_integer(
478
500
  data,
@@ -487,7 +509,7 @@ static VALUE data_append_float(VALUE self, VALUE value) {
487
509
 
488
510
  Check_Type(value, T_FLOAT);
489
511
 
490
- Data_Get_Struct(self, appsignal_data_t, data);
512
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
491
513
 
492
514
  appsignal_data_array_append_float(
493
515
  data,
@@ -500,7 +522,7 @@ static VALUE data_append_float(VALUE self, VALUE value) {
500
522
  static VALUE data_append_boolean(VALUE self, VALUE value) {
501
523
  appsignal_data_t* data;
502
524
 
503
- Data_Get_Struct(self, appsignal_data_t, data);
525
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
504
526
 
505
527
  appsignal_data_array_append_boolean(
506
528
  data,
@@ -513,7 +535,7 @@ static VALUE data_append_boolean(VALUE self, VALUE value) {
513
535
  static VALUE data_append_nil(VALUE self) {
514
536
  appsignal_data_t* data;
515
537
 
516
- Data_Get_Struct(self, appsignal_data_t, data);
538
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
517
539
 
518
540
  appsignal_data_array_append_null(data);
519
541
 
@@ -524,10 +546,9 @@ static VALUE data_append_data(VALUE self, VALUE value) {
524
546
  appsignal_data_t* data;
525
547
  appsignal_data_t* value_data;
526
548
 
527
- Check_Type(value, RUBY_T_DATA);
549
+ value_data = rb_check_typeddata(value, &data_data_type);
528
550
 
529
- Data_Get_Struct(self, appsignal_data_t, data);
530
- Data_Get_Struct(value, appsignal_data_t, value_data);
551
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
531
552
 
532
553
  appsignal_data_array_append_data(
533
554
  data,
@@ -541,12 +562,12 @@ static VALUE data_equal(VALUE self, VALUE other) {
541
562
  appsignal_data_t* data;
542
563
  appsignal_data_t* other_data;
543
564
 
544
- if (TYPE(other) != RUBY_T_DATA) {
565
+ if (TYPE(other) != T_DATA) {
545
566
  return Qfalse;
546
567
  }
547
568
 
548
- Data_Get_Struct(self, appsignal_data_t, data);
549
- Data_Get_Struct(other, appsignal_data_t, other_data);
569
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
570
+ TypedData_Get_Struct(other, appsignal_data_t, &data_data_type, other_data);
550
571
 
551
572
  if (appsignal_data_equal(data, other_data) == 1) {
552
573
  return Qtrue;
@@ -559,7 +580,7 @@ static VALUE data_to_s(VALUE self) {
559
580
  appsignal_data_t* data;
560
581
  appsignal_string_t json;
561
582
 
562
- Data_Get_Struct(self, appsignal_data_t, data);
583
+ TypedData_Get_Struct(self, appsignal_data_t, &data_data_type, data);
563
584
 
564
585
  json = appsignal_data_to_json(data);
565
586
 
@@ -578,7 +599,7 @@ static VALUE root_span_new(VALUE self, VALUE namespace) {
578
599
  span = appsignal_create_root_span(make_appsignal_string(namespace));
579
600
 
580
601
  if (span) {
581
- return Data_Wrap_Struct(Span, NULL, appsignal_free_span, span);
602
+ return TypedData_Wrap_Struct(Span, &span_data_type, span);
582
603
  } else {
583
604
  return Qnil;
584
605
  }
@@ -588,12 +609,12 @@ static VALUE child_span_new(VALUE self) {
588
609
  appsignal_span_t* parent;
589
610
  appsignal_span_t* span;
590
611
 
591
- Data_Get_Struct(self, appsignal_span_t, parent);
612
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, parent);
592
613
 
593
614
  span = appsignal_create_child_span(parent);
594
615
 
595
616
  if (span) {
596
- return Data_Wrap_Struct(Span, NULL, appsignal_free_span, span);
617
+ return TypedData_Wrap_Struct(Span, &span_data_type, span);
597
618
  } else {
598
619
  return Qnil;
599
620
  }
@@ -604,7 +625,7 @@ static VALUE set_span_name(VALUE self, VALUE name) {
604
625
 
605
626
  Check_Type(name, T_STRING);
606
627
 
607
- Data_Get_Struct(self, appsignal_span_t, span);
628
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
608
629
 
609
630
  appsignal_set_span_name(span, make_appsignal_string(name));
610
631
  return Qnil;
@@ -616,10 +637,10 @@ static VALUE add_span_error(VALUE self, VALUE name, VALUE message, VALUE backtra
616
637
 
617
638
  Check_Type(name, T_STRING);
618
639
  Check_Type(message, T_STRING);
619
- Check_Type(backtrace, RUBY_T_DATA);
620
640
 
621
- Data_Get_Struct(self, appsignal_span_t, span);
622
- Data_Get_Struct(backtrace, appsignal_data_t, backtrace_data);
641
+ backtrace_data = rb_check_typeddata(backtrace, &data_data_type);
642
+
643
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
623
644
 
624
645
  appsignal_add_span_error(
625
646
  span,
@@ -635,10 +656,10 @@ static VALUE set_span_sample_data(VALUE self, VALUE key, VALUE payload) {
635
656
  appsignal_data_t* payload_data;
636
657
 
637
658
  Check_Type(key, T_STRING);
638
- Check_Type(payload, RUBY_T_DATA);
639
659
 
640
- Data_Get_Struct(self, appsignal_span_t, span);
641
- Data_Get_Struct(payload, appsignal_data_t, payload_data);
660
+ payload_data = rb_check_typeddata(payload, &data_data_type);
661
+
662
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
642
663
 
643
664
  appsignal_set_span_sample_data(
644
665
  span,
@@ -654,7 +675,7 @@ static VALUE set_span_attribute_string(VALUE self, VALUE key, VALUE value) {
654
675
  Check_Type(key, T_STRING);
655
676
  Check_Type(value, T_STRING);
656
677
 
657
- Data_Get_Struct(self, appsignal_span_t, span);
678
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
658
679
 
659
680
  appsignal_set_span_attribute_string(
660
681
  span,
@@ -675,7 +696,7 @@ static VALUE set_span_attribute_int(VALUE self, VALUE key, VALUE value) {
675
696
  rb_raise(rb_eTypeError, "wrong argument type %s (expected Integer)", rb_obj_classname(value));
676
697
  }
677
698
 
678
- Data_Get_Struct(self, appsignal_span_t, span);
699
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
679
700
 
680
701
  appsignal_set_span_attribute_int(
681
702
  span,
@@ -691,7 +712,7 @@ static VALUE set_span_attribute_bool(VALUE self, VALUE key, VALUE value) {
691
712
 
692
713
  Check_Type(key, T_STRING);
693
714
 
694
- Data_Get_Struct(self, appsignal_span_t, span);
715
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
695
716
 
696
717
  appsignal_set_span_attribute_bool(
697
718
  span,
@@ -708,7 +729,7 @@ static VALUE set_span_attribute_double(VALUE self, VALUE key, VALUE value) {
708
729
  Check_Type(key, T_STRING);
709
730
  Check_Type(value, T_FLOAT);
710
731
 
711
- Data_Get_Struct(self, appsignal_span_t, span);
732
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
712
733
 
713
734
  appsignal_set_span_attribute_double(
714
735
  span,
@@ -723,7 +744,7 @@ static VALUE span_to_json(VALUE self) {
723
744
  appsignal_span_t* span;
724
745
  appsignal_string_t json;
725
746
 
726
- Data_Get_Struct(self, appsignal_span_t, span);
747
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
727
748
 
728
749
  json = appsignal_span_to_json(span);
729
750
 
@@ -737,7 +758,7 @@ static VALUE span_to_json(VALUE self) {
737
758
  static VALUE close_span(VALUE self) {
738
759
  appsignal_span_t* span;
739
760
 
740
- Data_Get_Struct(self, appsignal_span_t, span);
761
+ TypedData_Get_Struct(self, appsignal_span_t, &span_data_type, span);
741
762
 
742
763
  appsignal_close_span(span);
743
764
 
@@ -751,9 +772,8 @@ static VALUE a_log(VALUE self, VALUE group, VALUE severity, VALUE format, VALUE
751
772
  Check_Type(severity, T_FIXNUM);
752
773
  Check_Type(format, T_FIXNUM);
753
774
  Check_Type(message, T_STRING);
754
- Check_Type(attributes, RUBY_T_DATA);
755
775
 
756
- Data_Get_Struct(attributes, appsignal_data_t, attributes_data);
776
+ attributes_data = rb_check_typeddata(attributes, &data_data_type);
757
777
 
758
778
  appsignal_log(
759
779
  make_appsignal_string(group),
@@ -771,9 +791,8 @@ static VALUE set_gauge(VALUE self, VALUE key, VALUE value, VALUE tags) {
771
791
 
772
792
  Check_Type(key, T_STRING);
773
793
  Check_Type(value, T_FLOAT);
774
- Check_Type(tags, RUBY_T_DATA);
775
794
 
776
- Data_Get_Struct(tags, appsignal_data_t, tags_data);
795
+ tags_data = rb_check_typeddata(tags, &data_data_type);
777
796
 
778
797
  appsignal_set_gauge(
779
798
  make_appsignal_string(key),
@@ -788,9 +807,8 @@ static VALUE increment_counter(VALUE self, VALUE key, VALUE count, VALUE tags) {
788
807
 
789
808
  Check_Type(key, T_STRING);
790
809
  Check_Type(count, T_FLOAT);
791
- Check_Type(tags, RUBY_T_DATA);
792
810
 
793
- Data_Get_Struct(tags, appsignal_data_t, tags_data);
811
+ tags_data = rb_check_typeddata(tags, &data_data_type);
794
812
 
795
813
  appsignal_increment_counter(
796
814
  make_appsignal_string(key),
@@ -805,9 +823,8 @@ static VALUE add_distribution_value(VALUE self, VALUE key, VALUE value, VALUE ta
805
823
 
806
824
  Check_Type(key, T_STRING);
807
825
  Check_Type(value, T_FLOAT);
808
- Check_Type(tags, RUBY_T_DATA);
809
826
 
810
- Data_Get_Struct(tags, appsignal_data_t, tags_data);
827
+ tags_data = rb_check_typeddata(tags, &data_data_type);
811
828
 
812
829
  appsignal_add_distribution_value(
813
830
  make_appsignal_string(key),
@@ -821,7 +838,7 @@ static void track_allocation(rb_event_flag_t flag, VALUE arg1, VALUE arg2, ID ar
821
838
  appsignal_track_allocation();
822
839
  }
823
840
 
824
- static VALUE install_allocation_event_hook() {
841
+ static VALUE install_allocation_event_hook(VALUE self) {
825
842
  // This event hook is only available on Ruby 2.1 and 2.2
826
843
  #if defined(RUBY_INTERNAL_EVENT_NEWOBJ)
827
844
  rb_add_event_hook(
@@ -834,7 +851,7 @@ static VALUE install_allocation_event_hook() {
834
851
  return Qnil;
835
852
  }
836
853
 
837
- static VALUE running_in_container() {
854
+ static VALUE running_in_container(VALUE self) {
838
855
  return appsignal_running_in_container() == 1 ? Qtrue : Qfalse;
839
856
  }
840
857
 
data/ext/base.rb CHANGED
@@ -145,7 +145,9 @@ def download_archive(type)
145
145
  return open(*args)
146
146
  end
147
147
  rescue => error
148
- download_errors << "- URL: #{download_url}\n Error: #{error.class}: #{error.message}"
148
+ backtrace = error.backtrace.join("\n")
149
+ download_errors <<
150
+ "- URL: #{download_url}\n Error: #{error.class}: #{error.message}\n#{backtrace}"
149
151
  next
150
152
  end
151
153
  end
@@ -66,6 +66,61 @@ module Appsignal
66
66
  end
67
67
  end
68
68
  end
69
+
70
+ def deduplicate_cron!(events) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
71
+ # Remove redundant cron check-in events from the given list of events.
72
+ # This is done by removing redundant *pairs* of events -- that is,
73
+ # for each identifier, only send one complete pair of start and
74
+ # finish events. Remove all other complete pairs of start and finish
75
+ # events for that identifier, but keep any other start or finish events
76
+ # that don't have a matching pair.
77
+ #
78
+ # Note that this method assumes that the events in this list have already
79
+ # been rejected based on `Event.redundant?`, so we don't check to remove
80
+ # check-in events that are functionally identical.
81
+ start_digests = Hash.new { |h, k| h[k] = Set.new }
82
+ finish_digests = Hash.new { |h, k| h[k] = Set.new }
83
+ complete_digests = Hash.new { |h, k| h[k] = Set.new }
84
+ keep_digest = {}
85
+
86
+ # Compute a list of complete digests for each identifier, that is, digests
87
+ # for which both a start and finish cron check-in event exist. Store the
88
+ # last seen digest for each identifier as the one to keep.
89
+ events.each do |event|
90
+ if event[:check_in_type] == "cron"
91
+ if event[:kind] == "start"
92
+ start_digests[event[:identifier]] << event[:digest]
93
+ if finish_digests[event[:identifier]].include?(event[:digest])
94
+ complete_digests[event[:identifier]] << event[:digest]
95
+ keep_digest[event[:identifier]] = event[:digest]
96
+ end
97
+ elsif event[:kind] == "finish"
98
+ finish_digests[event[:identifier]] << event[:digest]
99
+ if start_digests[event[:identifier]].include?(event[:digest])
100
+ complete_digests[event[:identifier]] << event[:digest]
101
+ keep_digest[event[:identifier]] = event[:digest]
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ start_digests = nil
108
+ finish_digests = nil
109
+
110
+ events.reject! do |event|
111
+ # Do not remove events that are not cron check-in events or that
112
+ # have an unknown kind.
113
+ return false unless
114
+ event[:check_in_type] == "cron" && (
115
+ event[:kind] == "start" ||
116
+ event[:kind] == "finish")
117
+
118
+ # Remove any event that is part of a complete digest pair, except
119
+ # for the one digest that should be kept.
120
+ keep_digest[event[:identifier]] != event[:digest] &&
121
+ complete_digests[event[:identifier]].include?(event[:digest])
122
+ end
123
+ end
69
124
  end
70
125
  end
71
126
  end
@@ -95,7 +95,11 @@ module Appsignal
95
95
  description = Event.describe(events)
96
96
 
97
97
  begin
98
- response = CheckIn.transmitter.transmit(events, :format => :ndjson)
98
+ @transmitter ||= Transmitter.new(
99
+ "#{Appsignal.config[:logging_endpoint]}/check_ins/json"
100
+ )
101
+
102
+ response = @transmitter.transmit(events, :format => :ndjson)
99
103
 
100
104
  if (200...300).include?(response.code.to_i)
101
105
  Appsignal.internal_logger.debug("Transmitted #{description}")
@@ -157,7 +161,9 @@ module Appsignal
157
161
  # Push a copy of the events to the queue, and clear the events array.
158
162
  # This ensures that `@events` always contains events that have not
159
163
  # yet been pushed to the queue.
160
- @queue.push(@events.dup)
164
+ events = @events.dup
165
+ Event.deduplicate_cron!(events)
166
+ @queue.push(events)
161
167
  @events.clear
162
168
 
163
169
  start_waker(BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS)
@@ -3,6 +3,8 @@
3
3
  module Appsignal
4
4
  module CheckIn
5
5
  HEARTBEAT_CONTINUOUS_INTERVAL_SECONDS = 30
6
+ NEW_SCHEDULER_MUTEX = Mutex.new
7
+
6
8
  class << self
7
9
  # @api private
8
10
  def continuous_heartbeats
@@ -82,16 +84,15 @@ module Appsignal
82
84
  scheduler.schedule(event)
83
85
  end
84
86
 
85
- # @api private
86
- def transmitter
87
- @transmitter ||= Transmitter.new(
88
- "#{Appsignal.config[:logging_endpoint]}/check_ins/json"
89
- )
90
- end
91
-
92
87
  # @api private
93
88
  def scheduler
94
- @scheduler ||= Scheduler.new
89
+ return @scheduler if @scheduler
90
+
91
+ NEW_SCHEDULER_MUTEX.synchronize do
92
+ @scheduler ||= Scheduler.new
93
+ end
94
+
95
+ @scheduler
95
96
  end
96
97
 
97
98
  # @api private