chargebee 2.74.0 → 2.76.0
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile.lock +2 -2
- data/README.md +53 -0
- data/VERSION +1 -1
- data/chargebee.gemspec +12 -2
- data/lib/chargebee/environment.rb +3 -2
- data/lib/chargebee/models/addon.rb +7 -7
- data/lib/chargebee/models/address.rb +2 -2
- data/lib/chargebee/models/alert.rb +6 -6
- data/lib/chargebee/models/alert_status.rb +2 -2
- data/lib/chargebee/models/attached_item.rb +5 -5
- data/lib/chargebee/models/business_entity.rb +2 -2
- data/lib/chargebee/models/card.rb +5 -5
- data/lib/chargebee/models/comment.rb +4 -4
- data/lib/chargebee/models/configuration.rb +1 -1
- data/lib/chargebee/models/coupon.rb +9 -9
- data/lib/chargebee/models/coupon_code.rb +4 -4
- data/lib/chargebee/models/coupon_set.rb +7 -7
- data/lib/chargebee/models/credit_note.rb +14 -14
- data/lib/chargebee/models/csv_tax_rule.rb +6 -1
- data/lib/chargebee/models/currency.rb +6 -6
- data/lib/chargebee/models/customer.rb +26 -26
- data/lib/chargebee/models/customer_entitlement.rb +1 -1
- data/lib/chargebee/models/differential_price.rb +5 -5
- data/lib/chargebee/models/entitlement.rb +2 -2
- data/lib/chargebee/models/entitlement_override.rb +2 -2
- data/lib/chargebee/models/estimate.rb +20 -20
- data/lib/chargebee/models/event.rb +2 -2
- data/lib/chargebee/models/export.rb +18 -18
- data/lib/chargebee/models/feature.rb +8 -8
- data/lib/chargebee/models/gift.rb +7 -7
- data/lib/chargebee/models/grant_block.rb +1 -1
- data/lib/chargebee/models/hosted_page.rb +22 -22
- data/lib/chargebee/models/in_app_subscription.rb +4 -4
- data/lib/chargebee/models/invoice.rb +40 -40
- data/lib/chargebee/models/item.rb +5 -5
- data/lib/chargebee/models/item_entitlement.rb +4 -4
- data/lib/chargebee/models/item_family.rb +5 -5
- data/lib/chargebee/models/item_price.rb +7 -7
- data/lib/chargebee/models/ledger_account_balance.rb +1 -1
- data/lib/chargebee/models/ledger_operation.rb +6 -6
- data/lib/chargebee/models/non_subscription.rb +1 -1
- data/lib/chargebee/models/offer_event.rb +1 -1
- data/lib/chargebee/models/offer_fulfillment.rb +3 -3
- data/lib/chargebee/models/omnichannel_one_time_order.rb +2 -2
- data/lib/chargebee/models/omnichannel_subscription.rb +4 -4
- data/lib/chargebee/models/omnichannel_subscription_item.rb +1 -1
- data/lib/chargebee/models/order.rb +12 -12
- data/lib/chargebee/models/payment_intent.rb +3 -3
- data/lib/chargebee/models/payment_schedule_scheme.rb +3 -3
- data/lib/chargebee/models/payment_source.rb +16 -16
- data/lib/chargebee/models/payment_voucher.rb +4 -4
- data/lib/chargebee/models/personalized_offer.rb +1 -1
- data/lib/chargebee/models/plan.rb +7 -7
- data/lib/chargebee/models/portal_session.rb +4 -4
- data/lib/chargebee/models/price_variant.rb +5 -5
- data/lib/chargebee/models/pricing_page_session.rb +2 -2
- data/lib/chargebee/models/promotional_credit.rb +5 -5
- data/lib/chargebee/models/promotional_grant.rb +1 -1
- data/lib/chargebee/models/purchase.rb +2 -2
- data/lib/chargebee/models/quote.rb +26 -26
- data/lib/chargebee/models/ramp.rb +5 -5
- data/lib/chargebee/models/recorded_purchase.rb +2 -2
- data/lib/chargebee/models/resource_migration.rb +1 -1
- data/lib/chargebee/models/rule.rb +1 -1
- data/lib/chargebee/models/site_migration_detail.rb +1 -1
- data/lib/chargebee/models/subscription.rb +37 -37
- data/lib/chargebee/models/subscription_entitlement.rb +2 -2
- data/lib/chargebee/models/time_machine.rb +3 -3
- data/lib/chargebee/models/transaction.rb +11 -11
- data/lib/chargebee/models/unbilled_charge.rb +6 -6
- data/lib/chargebee/models/usage.rb +5 -5
- data/lib/chargebee/models/usage_charge.rb +1 -1
- data/lib/chargebee/models/usage_event.rb +2 -2
- data/lib/chargebee/models/usage_file.rb +2 -2
- data/lib/chargebee/models/usage_summary.rb +1 -1
- data/lib/chargebee/models/virtual_bank_account.rb +6 -6
- data/lib/chargebee/models/webhook_endpoint.rb +5 -5
- data/lib/chargebee/request.rb +37 -8
- data/lib/chargebee/telemetry/request_telemetry_context.rb +29 -0
- data/lib/chargebee/telemetry/request_telemetry_error.rb +20 -0
- data/lib/chargebee/telemetry/request_telemetry_result.rb +20 -0
- data/lib/chargebee/telemetry/telemetry_adapter.rb +32 -0
- data/lib/chargebee/telemetry/telemetry_attribute_keys.rb +33 -0
- data/lib/chargebee/telemetry/telemetry_support.rb +123 -0
- data/lib/chargebee/telemetry_executor.rb +95 -0
- data/lib/chargebee.rb +9 -1
- data/spec/chargebee/request_telemetry_spec.rb +75 -0
- data/spec/chargebee/telemetry_executor_spec.rb +147 -0
- data/spec/chargebee/telemetry_support_spec.rb +29 -0
- metadata +15 -2
|
@@ -14,7 +14,7 @@ module ChargeBee
|
|
|
14
14
|
options = {
|
|
15
15
|
:isIdempotent => true
|
|
16
16
|
}
|
|
17
|
-
Request.send('post', uri_path("virtual_bank_accounts","create_using_permanent_token"), params, env, headers,nil, false, jsonKeys, options)
|
|
17
|
+
Request.send('post', uri_path("virtual_bank_accounts","create_using_permanent_token"), params, env, headers,nil, false, jsonKeys, options, telemetry_resource: "virtualBankAccount", telemetry_operation: "createUsingPermanentToken")
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def self.create(params, env=nil, headers={})
|
|
@@ -23,21 +23,21 @@ module ChargeBee
|
|
|
23
23
|
options = {
|
|
24
24
|
:isIdempotent => true
|
|
25
25
|
}
|
|
26
|
-
Request.send('post', uri_path("virtual_bank_accounts"), params, env, headers,nil, false, jsonKeys, options)
|
|
26
|
+
Request.send('post', uri_path("virtual_bank_accounts"), params, env, headers,nil, false, jsonKeys, options, telemetry_resource: "virtualBankAccount", telemetry_operation: "create")
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def self.retrieve(id, env=nil, headers={})
|
|
30
30
|
jsonKeys = {
|
|
31
31
|
}
|
|
32
32
|
options = {}
|
|
33
|
-
Request.send('get', uri_path("virtual_bank_accounts",id.to_s), {}, env, headers,nil, false, jsonKeys, options)
|
|
33
|
+
Request.send('get', uri_path("virtual_bank_accounts",id.to_s), {}, env, headers,nil, false, jsonKeys, options, telemetry_resource: "virtualBankAccount", telemetry_operation: "retrieve")
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def self.list(params={}, env=nil, headers={})
|
|
37
37
|
jsonKeys = {
|
|
38
38
|
}
|
|
39
39
|
options = {}
|
|
40
|
-
Request.send_list_request('get', uri_path("virtual_bank_accounts"), params, env, headers,nil, false, jsonKeys, options)
|
|
40
|
+
Request.send_list_request('get', uri_path("virtual_bank_accounts"), params, env, headers,nil, false, jsonKeys, options, telemetry_resource: "virtualBankAccount", telemetry_operation: "list")
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def self.delete(id, env=nil, headers={})
|
|
@@ -46,7 +46,7 @@ module ChargeBee
|
|
|
46
46
|
options = {
|
|
47
47
|
:isIdempotent => true
|
|
48
48
|
}
|
|
49
|
-
Request.send('post', uri_path("virtual_bank_accounts",id.to_s,"delete"), {}, env, headers,nil, false, jsonKeys, options)
|
|
49
|
+
Request.send('post', uri_path("virtual_bank_accounts",id.to_s,"delete"), {}, env, headers,nil, false, jsonKeys, options, telemetry_resource: "virtualBankAccount", telemetry_operation: "delete")
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def self.delete_local(id, env=nil, headers={})
|
|
@@ -55,7 +55,7 @@ module ChargeBee
|
|
|
55
55
|
options = {
|
|
56
56
|
:isIdempotent => true
|
|
57
57
|
}
|
|
58
|
-
Request.send('post', uri_path("virtual_bank_accounts",id.to_s,"delete_local"), {}, env, headers,nil, false, jsonKeys, options)
|
|
58
|
+
Request.send('post', uri_path("virtual_bank_accounts",id.to_s,"delete_local"), {}, env, headers,nil, false, jsonKeys, options, telemetry_resource: "virtualBankAccount", telemetry_operation: "deleteLocal")
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
end # ~VirtualBankAccount
|
|
@@ -13,7 +13,7 @@ module ChargeBee
|
|
|
13
13
|
options = {
|
|
14
14
|
:isIdempotent => true
|
|
15
15
|
}
|
|
16
|
-
Request.send('post', uri_path("webhook_endpoints"), params, env, headers,nil, false, jsonKeys, options)
|
|
16
|
+
Request.send('post', uri_path("webhook_endpoints"), params, env, headers,nil, false, jsonKeys, options, telemetry_resource: "webhookEndpoint", telemetry_operation: "create")
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def self.update(id, params={}, env=nil, headers={})
|
|
@@ -22,14 +22,14 @@ module ChargeBee
|
|
|
22
22
|
options = {
|
|
23
23
|
:isIdempotent => true
|
|
24
24
|
}
|
|
25
|
-
Request.send('post', uri_path("webhook_endpoints",id.to_s), params, env, headers,nil, false, jsonKeys, options)
|
|
25
|
+
Request.send('post', uri_path("webhook_endpoints",id.to_s), params, env, headers,nil, false, jsonKeys, options, telemetry_resource: "webhookEndpoint", telemetry_operation: "update")
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def self.retrieve(id, env=nil, headers={})
|
|
29
29
|
jsonKeys = {
|
|
30
30
|
}
|
|
31
31
|
options = {}
|
|
32
|
-
Request.send('get', uri_path("webhook_endpoints",id.to_s), {}, env, headers,nil, false, jsonKeys, options)
|
|
32
|
+
Request.send('get', uri_path("webhook_endpoints",id.to_s), {}, env, headers,nil, false, jsonKeys, options, telemetry_resource: "webhookEndpoint", telemetry_operation: "retrieve")
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def self.delete(id, env=nil, headers={})
|
|
@@ -38,14 +38,14 @@ module ChargeBee
|
|
|
38
38
|
options = {
|
|
39
39
|
:isIdempotent => true
|
|
40
40
|
}
|
|
41
|
-
Request.send('post', uri_path("webhook_endpoints",id.to_s,"delete"), {}, env, headers,nil, false, jsonKeys, options)
|
|
41
|
+
Request.send('post', uri_path("webhook_endpoints",id.to_s,"delete"), {}, env, headers,nil, false, jsonKeys, options, telemetry_resource: "webhookEndpoint", telemetry_operation: "delete")
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def self.list(params={}, env=nil, headers={})
|
|
45
45
|
jsonKeys = {
|
|
46
46
|
}
|
|
47
47
|
options = {}
|
|
48
|
-
Request.send_list_request('get', uri_path("webhook_endpoints"), params, env, headers,nil, false, jsonKeys, options)
|
|
48
|
+
Request.send_list_request('get', uri_path("webhook_endpoints"), params, env, headers,nil, false, jsonKeys, options, telemetry_resource: "webhookEndpoint", telemetry_operation: "list")
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
end # ~WebhookEndpoint
|
data/lib/chargebee/request.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module ChargeBee
|
|
2
2
|
class Request
|
|
3
3
|
|
|
4
|
-
def self.send_list_request(method, url, params={}, env=nil, headers={}, sub_domain=nil, isJsonRequest=nil, jsonKeys={}, options={})
|
|
4
|
+
def self.send_list_request(method, url, params={}, env=nil, headers={}, sub_domain=nil, isJsonRequest=nil, jsonKeys={}, options={}, telemetry_resource=nil, telemetry_operation=nil)
|
|
5
5
|
serialized = {}
|
|
6
6
|
params.each do |k, v|
|
|
7
7
|
if(v.kind_of? Array)
|
|
@@ -9,19 +9,48 @@ module ChargeBee
|
|
|
9
9
|
end
|
|
10
10
|
serialized["#{k}"] = v
|
|
11
11
|
end
|
|
12
|
-
self.send(method, url, serialized, env, headers, sub_domain, isJsonRequest
|
|
12
|
+
self.send(method, url, serialized, env, headers, sub_domain, isJsonRequest, jsonKeys, options, telemetry_resource, telemetry_operation)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def self.send(method, url, params={}, env=nil, headers={}, sub_domain=nil, isJsonRequest=nil, jsonKeys={}, options={})
|
|
15
|
+
def self.send(method, url, params={}, env=nil, headers={}, sub_domain=nil, isJsonRequest=nil, jsonKeys={}, options={}, telemetry_resource=nil, telemetry_operation=nil)
|
|
16
|
+
telemetry_resource, telemetry_operation = normalize_telemetry_args(telemetry_resource, telemetry_operation)
|
|
16
17
|
env ||= ChargeBee.default_env
|
|
17
18
|
ser_params = isJsonRequest ? params : Util.serialize(params, nil, nil, jsonKeys)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
http_url = TelemetryExecutor.build_http_url(env, sub_domain, url)
|
|
20
|
+
normalized_headers = headers || {}
|
|
21
|
+
|
|
22
|
+
TelemetryExecutor.execute(
|
|
23
|
+
env,
|
|
24
|
+
telemetry_resource: telemetry_resource,
|
|
25
|
+
telemetry_operation: telemetry_operation,
|
|
26
|
+
method: method,
|
|
27
|
+
http_url: http_url,
|
|
28
|
+
request_headers: normalized_headers,
|
|
29
|
+
) do |telemetry_headers|
|
|
30
|
+
merged_headers = normalized_headers.dup
|
|
31
|
+
if telemetry_headers
|
|
32
|
+
telemetry_headers.each { |key, value| merged_headers[key] = value }
|
|
33
|
+
end
|
|
34
|
+
resp, rheaders, rcode = NativeRequest.request(method, url, env, ser_params||={}, merged_headers, sub_domain, isJsonRequest, options)
|
|
35
|
+
result = if resp && resp.has_key?(:list)
|
|
36
|
+
ListResult.new(resp[:list], resp[:next_offset], rheaders, rcode)
|
|
37
|
+
else
|
|
38
|
+
Result.new(resp, rheaders, rcode)
|
|
39
|
+
end
|
|
40
|
+
[rcode.to_i, result]
|
|
23
41
|
end
|
|
24
42
|
end
|
|
25
43
|
|
|
44
|
+
def self.normalize_telemetry_args(telemetry_resource, telemetry_operation)
|
|
45
|
+
if telemetry_resource.is_a?(Hash) && telemetry_operation.nil? &&
|
|
46
|
+
(telemetry_resource.key?(:telemetry_resource) || telemetry_resource.key?(:telemetry_operation))
|
|
47
|
+
h = telemetry_resource
|
|
48
|
+
return [h[:telemetry_resource], h[:telemetry_operation]]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
[telemetry_resource, telemetry_operation]
|
|
52
|
+
end
|
|
53
|
+
private_class_method :normalize_telemetry_args
|
|
54
|
+
|
|
26
55
|
end
|
|
27
56
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# This file is auto-generated by Chargebee.
|
|
2
|
+
# For more information on how to make changes to this file, please see the README.
|
|
3
|
+
# Reach out to dx@chargebee.com for any questions.
|
|
4
|
+
# Copyright 2026 Chargebee Inc.
|
|
5
|
+
|
|
6
|
+
module ChargeBee
|
|
7
|
+
module Telemetry
|
|
8
|
+
# Context passed to TelemetryAdapter#on_request_start.
|
|
9
|
+
class RequestTelemetryContext
|
|
10
|
+
attr_reader :span_name, :resource, :operation, :http_method, :http_url, :server_address,
|
|
11
|
+
:chargebee_site, :chargebee_api_version, :sdk_name, :sdk_version, :start_attributes
|
|
12
|
+
|
|
13
|
+
def initialize(span_name:, resource:, operation:, http_method:, http_url:, server_address:,
|
|
14
|
+
chargebee_site:, chargebee_api_version:, sdk_name:, sdk_version:, start_attributes:)
|
|
15
|
+
@span_name = span_name
|
|
16
|
+
@resource = resource
|
|
17
|
+
@operation = operation
|
|
18
|
+
@http_method = http_method
|
|
19
|
+
@http_url = http_url
|
|
20
|
+
@server_address = server_address
|
|
21
|
+
@chargebee_site = chargebee_site
|
|
22
|
+
@chargebee_api_version = chargebee_api_version
|
|
23
|
+
@sdk_name = sdk_name
|
|
24
|
+
@sdk_version = sdk_version
|
|
25
|
+
@start_attributes = start_attributes.freeze
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# This file is auto-generated by Chargebee.
|
|
2
|
+
# For more information on how to make changes to this file, please see the README.
|
|
3
|
+
# Reach out to dx@chargebee.com for any questions.
|
|
4
|
+
# Copyright 2026 Chargebee Inc.
|
|
5
|
+
|
|
6
|
+
module ChargeBee
|
|
7
|
+
module Telemetry
|
|
8
|
+
# Error details attached to RequestTelemetryResult on failed requests.
|
|
9
|
+
class RequestTelemetryError
|
|
10
|
+
attr_reader :message, :chargebee_error_code, :chargebee_api_error_type, :chargebee_error_param
|
|
11
|
+
|
|
12
|
+
def initialize(message:, chargebee_error_code: nil, chargebee_api_error_type: nil, chargebee_error_param: nil)
|
|
13
|
+
@message = message
|
|
14
|
+
@chargebee_error_code = chargebee_error_code
|
|
15
|
+
@chargebee_api_error_type = chargebee_api_error_type
|
|
16
|
+
@chargebee_error_param = chargebee_error_param
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# This file is auto-generated by Chargebee.
|
|
2
|
+
# For more information on how to make changes to this file, please see the README.
|
|
3
|
+
# Reach out to dx@chargebee.com for any questions.
|
|
4
|
+
# Copyright 2026 Chargebee Inc.
|
|
5
|
+
|
|
6
|
+
module ChargeBee
|
|
7
|
+
module Telemetry
|
|
8
|
+
# Result passed to TelemetryAdapter#on_request_end.
|
|
9
|
+
class RequestTelemetryResult
|
|
10
|
+
attr_reader :http_status_code, :duration_ms, :error, :end_attributes
|
|
11
|
+
|
|
12
|
+
def initialize(http_status_code:, duration_ms:, error:, end_attributes:)
|
|
13
|
+
@http_status_code = http_status_code
|
|
14
|
+
@duration_ms = duration_ms
|
|
15
|
+
@error = error
|
|
16
|
+
@end_attributes = end_attributes.freeze
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# This file is auto-generated by Chargebee.
|
|
2
|
+
# For more information on how to make changes to this file, please see the README.
|
|
3
|
+
# Reach out to dx@chargebee.com for any questions.
|
|
4
|
+
# Copyright 2026 Chargebee Inc.
|
|
5
|
+
|
|
6
|
+
module ChargeBee
|
|
7
|
+
module Telemetry
|
|
8
|
+
# Optional telemetry adapter for observability integrations (e.g. OpenTelemetry).
|
|
9
|
+
#
|
|
10
|
+
# When not configured, the SDK skips all telemetry work — zero overhead. The SDK stores the
|
|
11
|
+
# adapter by reference and never clones or deep-copies it.
|
|
12
|
+
#
|
|
13
|
+
# Implementations may inject W3C trace context headers (traceparent, tracestate) into
|
|
14
|
+
# request_headers during on_request_start.
|
|
15
|
+
module TelemetryAdapter
|
|
16
|
+
# Called once per SDK API call before the request is sent (including before retries).
|
|
17
|
+
#
|
|
18
|
+
# context contains prebuilt start attributes. request_headers is a mutable map for trace propagation.
|
|
19
|
+
# Returns an opaque handle passed back to on_request_end, or nil if span creation was skipped.
|
|
20
|
+
def on_request_start(context, request_headers)
|
|
21
|
+
raise NotImplementedError
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Called once per SDK API call after the final response or terminal failure.
|
|
25
|
+
#
|
|
26
|
+
# handle is the value returned from on_request_start and may be nil. result contains prebuilt end attributes.
|
|
27
|
+
def on_request_end(handle, result)
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# This file is auto-generated by Chargebee.
|
|
2
|
+
# For more information on how to make changes to this file, please see the README.
|
|
3
|
+
# Reach out to dx@chargebee.com for any questions.
|
|
4
|
+
# Copyright 2026 Chargebee Inc.
|
|
5
|
+
|
|
6
|
+
module ChargeBee
|
|
7
|
+
module Telemetry
|
|
8
|
+
# Span attribute keys shared across Chargebee SDKs.
|
|
9
|
+
module TelemetryAttributeKeys
|
|
10
|
+
SDK_NAME = 'chargebee-ruby'.freeze
|
|
11
|
+
TELEMETRY_SPAN_NAME_PREFIX = 'chargebee'.freeze
|
|
12
|
+
|
|
13
|
+
HTTP_REQUEST_HEADER_ATTRIBUTE_PREFIX = 'http.request.header.'.freeze
|
|
14
|
+
CHARGEBEE_TELEMETRY_HEADER_PREFIX = 'chargebee-'.freeze
|
|
15
|
+
CHARGEBEE_TELEMETRY_HEADER_EXCLUDE_PREFIX = 'chargebee-request-origin-'.freeze
|
|
16
|
+
|
|
17
|
+
URL_FULL = 'url.full'.freeze
|
|
18
|
+
HTTP_REQUEST_METHOD = 'http.request.method'.freeze
|
|
19
|
+
HTTP_RESPONSE_STATUS_CODE = 'http.response.status_code'.freeze
|
|
20
|
+
SERVER_ADDRESS = 'server.address'.freeze
|
|
21
|
+
ERROR_TYPE = 'error.type'.freeze
|
|
22
|
+
CHARGEBEE_SITE = 'chargebee.site'.freeze
|
|
23
|
+
CHARGEBEE_API_VERSION = 'chargebee.api_version'.freeze
|
|
24
|
+
CHARGEBEE_RESOURCE = 'chargebee.resource'.freeze
|
|
25
|
+
CHARGEBEE_OPERATION = 'chargebee.operation'.freeze
|
|
26
|
+
CHARGEBEE_SDK_NAME = 'chargebee.sdk.name'.freeze
|
|
27
|
+
CHARGEBEE_SDK_VERSION = 'chargebee.sdk.version'.freeze
|
|
28
|
+
CHARGEBEE_ERROR_CODE = 'chargebee.error.code'.freeze
|
|
29
|
+
CHARGEBEE_ERROR_TYPE = 'chargebee.error.type'.freeze
|
|
30
|
+
CHARGEBEE_ERROR_PARAM = 'chargebee.error.param'.freeze
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# This file is auto-generated by Chargebee.
|
|
2
|
+
# For more information on how to make changes to this file, please see the README.
|
|
3
|
+
# Reach out to dx@chargebee.com for any questions.
|
|
4
|
+
# Copyright 2026 Chargebee Inc.
|
|
5
|
+
|
|
6
|
+
module ChargeBee
|
|
7
|
+
module Telemetry
|
|
8
|
+
# Helpers for building standardized Chargebee telemetry context and results.
|
|
9
|
+
class TelemetrySupport
|
|
10
|
+
class << self
|
|
11
|
+
def build_span_name(resource, operation)
|
|
12
|
+
"#{TelemetryAttributeKeys::TELEMETRY_SPAN_NAME_PREFIX}.#{resource}.#{operation}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def resolve_chargebee_api_version(api_path)
|
|
16
|
+
api_path == '/api/v1' ? 'v1' : 'v2'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def build_request_start_span_attributes(resource, operation, http_method, http_url, server_address,
|
|
20
|
+
chargebee_site, chargebee_api_version, sdk_version, request_headers = {})
|
|
21
|
+
{
|
|
22
|
+
TelemetryAttributeKeys::URL_FULL => http_url,
|
|
23
|
+
TelemetryAttributeKeys::HTTP_REQUEST_METHOD => http_method,
|
|
24
|
+
TelemetryAttributeKeys::SERVER_ADDRESS => server_address,
|
|
25
|
+
TelemetryAttributeKeys::CHARGEBEE_SITE => chargebee_site,
|
|
26
|
+
TelemetryAttributeKeys::CHARGEBEE_API_VERSION => chargebee_api_version,
|
|
27
|
+
TelemetryAttributeKeys::CHARGEBEE_RESOURCE => resource,
|
|
28
|
+
TelemetryAttributeKeys::CHARGEBEE_OPERATION => operation,
|
|
29
|
+
TelemetryAttributeKeys::CHARGEBEE_SDK_NAME => TelemetryAttributeKeys::SDK_NAME,
|
|
30
|
+
TelemetryAttributeKeys::CHARGEBEE_SDK_VERSION => sdk_version,
|
|
31
|
+
}.merge(build_request_header_span_attributes(request_headers))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Promotes chargebee-* request headers to http.request.header.* attributes; excludes the chargebee-request-origin-* PII family.
|
|
35
|
+
def build_request_header_span_attributes(request_headers)
|
|
36
|
+
attributes = {}
|
|
37
|
+
return attributes if request_headers.nil?
|
|
38
|
+
|
|
39
|
+
request_headers.each do |name, value|
|
|
40
|
+
next if name.nil? || value.nil?
|
|
41
|
+
|
|
42
|
+
lower_name = name.to_s.downcase
|
|
43
|
+
next unless lower_name.start_with?(TelemetryAttributeKeys::CHARGEBEE_TELEMETRY_HEADER_PREFIX)
|
|
44
|
+
next if lower_name.start_with?(TelemetryAttributeKeys::CHARGEBEE_TELEMETRY_HEADER_EXCLUDE_PREFIX)
|
|
45
|
+
|
|
46
|
+
attributes["#{TelemetryAttributeKeys::HTTP_REQUEST_HEADER_ATTRIBUTE_PREFIX}#{lower_name}"] = value.to_s
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
attributes
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def build_request_end_span_attributes(http_status_code, error)
|
|
53
|
+
attributes = {
|
|
54
|
+
TelemetryAttributeKeys::HTTP_RESPONSE_STATUS_CODE => http_status_code,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if error
|
|
58
|
+
if error.chargebee_api_error_type
|
|
59
|
+
attributes[TelemetryAttributeKeys::ERROR_TYPE] = error.chargebee_api_error_type
|
|
60
|
+
attributes[TelemetryAttributeKeys::CHARGEBEE_ERROR_TYPE] = error.chargebee_api_error_type
|
|
61
|
+
end
|
|
62
|
+
attributes[TelemetryAttributeKeys::CHARGEBEE_ERROR_CODE] = error.chargebee_error_code if error.chargebee_error_code
|
|
63
|
+
attributes[TelemetryAttributeKeys::CHARGEBEE_ERROR_PARAM] = error.chargebee_error_param if error.chargebee_error_param
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
attributes
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def build_request_telemetry_context(resource, operation, http_method, http_url, server_address,
|
|
70
|
+
chargebee_site, chargebee_api_version, sdk_version, request_headers = {})
|
|
71
|
+
RequestTelemetryContext.new(
|
|
72
|
+
span_name: build_span_name(resource, operation),
|
|
73
|
+
resource: resource,
|
|
74
|
+
operation: operation,
|
|
75
|
+
http_method: http_method,
|
|
76
|
+
http_url: http_url,
|
|
77
|
+
server_address: server_address,
|
|
78
|
+
chargebee_site: chargebee_site,
|
|
79
|
+
chargebee_api_version: chargebee_api_version,
|
|
80
|
+
sdk_name: TelemetryAttributeKeys::SDK_NAME,
|
|
81
|
+
sdk_version: sdk_version,
|
|
82
|
+
start_attributes: build_request_start_span_attributes(
|
|
83
|
+
resource, operation, http_method, http_url, server_address, chargebee_site, chargebee_api_version, sdk_version, request_headers
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def build_request_telemetry_result(http_status_code, duration_ms, error)
|
|
89
|
+
RequestTelemetryResult.new(
|
|
90
|
+
http_status_code: http_status_code,
|
|
91
|
+
duration_ms: duration_ms,
|
|
92
|
+
error: error,
|
|
93
|
+
end_attributes: build_request_end_span_attributes(http_status_code, error),
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def extract_request_telemetry_error(err)
|
|
98
|
+
return nil if err.nil?
|
|
99
|
+
|
|
100
|
+
message = err.message.to_s
|
|
101
|
+
message = 'Chargebee API request failed' if message.empty?
|
|
102
|
+
|
|
103
|
+
if err.is_a?(ChargeBee::APIError)
|
|
104
|
+
return RequestTelemetryError.new(
|
|
105
|
+
message: message,
|
|
106
|
+
chargebee_error_code: err.api_error_code,
|
|
107
|
+
chargebee_api_error_type: err.type.to_s,
|
|
108
|
+
chargebee_error_param: err.param,
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
RequestTelemetryError.new(message: message)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def extract_http_status_code(err)
|
|
116
|
+
return err.http_status_code if err.is_a?(ChargeBee::APIError)
|
|
117
|
+
|
|
118
|
+
nil
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
module ChargeBee
|
|
4
|
+
class TelemetryExecutor
|
|
5
|
+
class << self
|
|
6
|
+
def execute(env, telemetry_resource:, telemetry_operation:, method:, http_url:, request_headers: {})
|
|
7
|
+
adapter = env.telemetry_adapter
|
|
8
|
+
if adapter.nil? || telemetry_resource.to_s.empty? || telemetry_operation.to_s.empty?
|
|
9
|
+
_status, result = yield(nil)
|
|
10
|
+
return result
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
14
|
+
headers = {}
|
|
15
|
+
handle = start_telemetry(
|
|
16
|
+
env, adapter, telemetry_resource, telemetry_operation, method, http_url, request_headers, headers
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
telemetry_headers = headers.empty? ? nil : headers
|
|
21
|
+
status_code, result = yield(telemetry_headers)
|
|
22
|
+
end_telemetry_success(adapter, handle, start, status_code)
|
|
23
|
+
result
|
|
24
|
+
rescue => err
|
|
25
|
+
end_telemetry_failure(adapter, handle, start, err)
|
|
26
|
+
raise
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def build_http_url(env, sub_domain, url)
|
|
31
|
+
path = url.start_with?('/') ? url : "/#{url}"
|
|
32
|
+
full = env.api_url(path, sub_domain)
|
|
33
|
+
uri = URI.parse(full)
|
|
34
|
+
"#{uri.scheme}://#{uri.host}#{uri.path}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def start_telemetry(env, adapter, resource, operation, method, http_url, request_headers, headers)
|
|
40
|
+
uri = URI.parse(http_url)
|
|
41
|
+
host = uri.host || ''
|
|
42
|
+
api_path = "/api/#{Environment::API_VERSION}"
|
|
43
|
+
context = Telemetry::TelemetrySupport.build_request_telemetry_context(
|
|
44
|
+
resource,
|
|
45
|
+
operation,
|
|
46
|
+
method.to_s.upcase,
|
|
47
|
+
http_url,
|
|
48
|
+
host,
|
|
49
|
+
env.site,
|
|
50
|
+
Telemetry::TelemetrySupport.resolve_chargebee_api_version(api_path),
|
|
51
|
+
ChargeBee::VERSION,
|
|
52
|
+
request_headers,
|
|
53
|
+
)
|
|
54
|
+
safe_on_request_start(env, adapter, context, headers)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def end_telemetry_success(adapter, handle, start, http_status_code)
|
|
58
|
+
duration_ms = elapsed_ms(start)
|
|
59
|
+
result = Telemetry::TelemetrySupport.build_request_telemetry_result(http_status_code, duration_ms, nil)
|
|
60
|
+
safe_on_request_end(adapter, handle, result)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def end_telemetry_failure(adapter, handle, start, err)
|
|
64
|
+
status_code = Telemetry::TelemetrySupport.extract_http_status_code(err) || 500
|
|
65
|
+
duration_ms = elapsed_ms(start)
|
|
66
|
+
telemetry_error = Telemetry::TelemetrySupport.extract_request_telemetry_error(err)
|
|
67
|
+
result = Telemetry::TelemetrySupport.build_request_telemetry_result(status_code, duration_ms, telemetry_error)
|
|
68
|
+
safe_on_request_end(adapter, handle, result)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def safe_on_request_start(env, adapter, context, headers)
|
|
72
|
+
adapter.on_request_start(context, headers)
|
|
73
|
+
rescue => err
|
|
74
|
+
log_telemetry_error(env, 'on_request_start', err)
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def safe_on_request_end(adapter, handle, result)
|
|
79
|
+
adapter.on_request_end(handle, result)
|
|
80
|
+
rescue => err
|
|
81
|
+
warn "[ChargeBee] Telemetry adapter on_request_end failed: #{err}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def log_telemetry_error(env, phase, err)
|
|
85
|
+
return unless env.enable_debug_logs
|
|
86
|
+
|
|
87
|
+
warn "[ChargeBee] Telemetry adapter #{phase} failed: #{err}. Continuing without telemetry."
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def elapsed_ms(start)
|
|
91
|
+
((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
data/lib/chargebee.rb
CHANGED
|
@@ -7,6 +7,14 @@ require File.dirname(__FILE__) + '/chargebee/list_result'
|
|
|
7
7
|
|
|
8
8
|
require File.dirname(__FILE__) + '/chargebee/errors'
|
|
9
9
|
|
|
10
|
+
require File.dirname(__FILE__) + '/chargebee/telemetry/telemetry_attribute_keys'
|
|
11
|
+
require File.dirname(__FILE__) + '/chargebee/telemetry/request_telemetry_context'
|
|
12
|
+
require File.dirname(__FILE__) + '/chargebee/telemetry/request_telemetry_error'
|
|
13
|
+
require File.dirname(__FILE__) + '/chargebee/telemetry/request_telemetry_result'
|
|
14
|
+
require File.dirname(__FILE__) + '/chargebee/telemetry/telemetry_adapter'
|
|
15
|
+
require File.dirname(__FILE__) + '/chargebee/telemetry/telemetry_support'
|
|
16
|
+
require File.dirname(__FILE__) + '/chargebee/telemetry_executor'
|
|
17
|
+
|
|
10
18
|
require File.dirname(__FILE__) + '/chargebee/models/model'
|
|
11
19
|
require File.dirname(__FILE__) + '/chargebee/models/addon'
|
|
12
20
|
require File.dirname(__FILE__) + '/chargebee/models/address'
|
|
@@ -121,7 +129,7 @@ require File.dirname(__FILE__) + '/chargebee/models/webhook_endpoint'
|
|
|
121
129
|
|
|
122
130
|
module ChargeBee
|
|
123
131
|
|
|
124
|
-
VERSION = '2.
|
|
132
|
+
VERSION = '2.76.0'
|
|
125
133
|
|
|
126
134
|
@@default_env = nil
|
|
127
135
|
@@verify_ca_certs = true
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ChargeBee::Request do
|
|
4
|
+
class InjectTraceAdapter
|
|
5
|
+
include ChargeBee::Telemetry::TelemetryAdapter
|
|
6
|
+
|
|
7
|
+
def on_request_start(_context, request_headers)
|
|
8
|
+
request_headers['traceparent'] = '00-test-trace'
|
|
9
|
+
nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def on_request_end(_handle, _result)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'does not mutate caller headers when telemetry injects trace headers' do
|
|
17
|
+
env = ChargeBee::Environment.new(
|
|
18
|
+
api_key: 'test_key',
|
|
19
|
+
site: 'acme',
|
|
20
|
+
telemetry_adapter: InjectTraceAdapter.new,
|
|
21
|
+
)
|
|
22
|
+
original_headers = { 'chargebee-foo' => 'bar' }
|
|
23
|
+
headers = original_headers.dup
|
|
24
|
+
|
|
25
|
+
ChargeBee::NativeRequest.expects(:request).with do |_method, _url, _env, _params, merged_headers, *_rest|
|
|
26
|
+
expect(merged_headers['traceparent']).to eq('00-test-trace')
|
|
27
|
+
expect(merged_headers['chargebee-foo']).to eq('bar')
|
|
28
|
+
true
|
|
29
|
+
end.returns([{}, {}, '200'])
|
|
30
|
+
|
|
31
|
+
ChargeBee::Request.send(
|
|
32
|
+
'get',
|
|
33
|
+
'/customers',
|
|
34
|
+
{},
|
|
35
|
+
env,
|
|
36
|
+
headers,
|
|
37
|
+
nil,
|
|
38
|
+
false,
|
|
39
|
+
{},
|
|
40
|
+
{},
|
|
41
|
+
telemetry_resource: 'customer',
|
|
42
|
+
telemetry_operation: 'list',
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
expect(headers).to eq(original_headers)
|
|
46
|
+
expect(headers).not_to have_key('traceparent')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'accepts nil headers when telemetry injects trace headers' do
|
|
50
|
+
env = ChargeBee::Environment.new(
|
|
51
|
+
api_key: 'test_key',
|
|
52
|
+
site: 'acme',
|
|
53
|
+
telemetry_adapter: InjectTraceAdapter.new,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
ChargeBee::NativeRequest.expects(:request).with do |_method, _url, _env, _params, merged_headers, *_rest|
|
|
57
|
+
expect(merged_headers['traceparent']).to eq('00-test-trace')
|
|
58
|
+
true
|
|
59
|
+
end.returns([{}, {}, '200'])
|
|
60
|
+
|
|
61
|
+
ChargeBee::Request.send(
|
|
62
|
+
'get',
|
|
63
|
+
'/customers',
|
|
64
|
+
{},
|
|
65
|
+
env,
|
|
66
|
+
nil,
|
|
67
|
+
nil,
|
|
68
|
+
false,
|
|
69
|
+
{},
|
|
70
|
+
{},
|
|
71
|
+
'customer',
|
|
72
|
+
'list',
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
end
|