11package io .sentry .metrics ;
22
3+ import io .sentry .HostnameCache ;
4+ import io .sentry .IScope ;
5+ import io .sentry .ISpan ;
6+ import io .sentry .PropagationContext ;
37import io .sentry .Scopes ;
8+ import io .sentry .SentryAttribute ;
9+ import io .sentry .SentryAttributeType ;
10+ import io .sentry .SentryAttributes ;
11+ import io .sentry .SentryDate ;
12+ import io .sentry .SentryLevel ;
13+ import io .sentry .SentryLogEventAttributeValue ;
14+ import io .sentry .SentryMetricsEvent ;
15+ import io .sentry .SentryOptions ;
16+ import io .sentry .SpanId ;
17+ import io .sentry .logger .SentryLogParameters ;
18+ import io .sentry .protocol .SdkVersion ;
19+ import io .sentry .protocol .SentryId ;
20+ import io .sentry .protocol .User ;
21+ import io .sentry .util .Platform ;
22+ import io .sentry .util .TracingUtils ;
23+ import java .util .HashMap ;
424import org .jetbrains .annotations .NotNull ;
25+ import org .jetbrains .annotations .Nullable ;
526
627public final class MetricsApi implements IMetricsApi {
728
@@ -13,6 +34,196 @@ public MetricsApi(final @NotNull Scopes scopes) {
1334
1435 @ Override
1536 public void count (@ NotNull String name ) {
16- scopes .getOptions ();
37+ captureMetrics (SentryLogParameters .create (null , null ), name , "counter" , 1.0 );
38+ }
39+
40+ @ SuppressWarnings ("AnnotateFormatMethod" )
41+ private void captureMetrics (
42+ final @ NotNull SentryLogParameters params ,
43+ final @ Nullable String name ,
44+ final @ Nullable String type ,
45+ final @ Nullable Double value ) {
46+ final @ NotNull SentryOptions options = scopes .getOptions ();
47+ try {
48+ if (!scopes .isEnabled ()) {
49+ options
50+ .getLogger ()
51+ .log (SentryLevel .WARNING , "Instance is disabled and this 'metrics' call is a no-op." );
52+ return ;
53+ }
54+
55+ if (!options .getMetrics ().isEnabled ()) {
56+ options
57+ .getLogger ()
58+ .log (
59+ SentryLevel .WARNING ,
60+ "Sentry Metrics is disabled and this 'metrics' call is a no-op." );
61+ return ;
62+ }
63+
64+ if (name == null ) {
65+ return ;
66+ }
67+
68+ if (type == null ) {
69+ return ;
70+ }
71+
72+ if (value == null ) {
73+ return ;
74+ }
75+
76+ final @ Nullable SentryDate timestamp = params .getTimestamp ();
77+ final @ NotNull SentryDate timestampToUse =
78+ timestamp == null ? options .getDateProvider ().now () : timestamp ;
79+
80+ final @ NotNull IScope combinedScope = scopes .getCombinedScopeView ();
81+ final @ NotNull PropagationContext propagationContext = combinedScope .getPropagationContext ();
82+ final @ Nullable ISpan span = combinedScope .getSpan ();
83+ if (span == null ) {
84+ TracingUtils .maybeUpdateBaggage (combinedScope , options );
85+ }
86+ final @ NotNull SentryId traceId =
87+ span == null ? propagationContext .getTraceId () : span .getSpanContext ().getTraceId ();
88+ final @ NotNull SpanId spanId =
89+ span == null ? propagationContext .getSpanId () : span .getSpanContext ().getSpanId ();
90+ final SentryMetricsEvent metricsEvent =
91+ new SentryMetricsEvent (traceId , timestampToUse , name , type , value );
92+ metricsEvent .setSpanId (spanId );
93+ metricsEvent .setAttributes (createAttributes (params ));
94+
95+ scopes .getClient ().captureMetric (metricsEvent , combinedScope );
96+ } catch (Throwable e ) {
97+ options .getLogger ().log (SentryLevel .ERROR , "Error while capturing log event" , e );
98+ }
99+ }
100+
101+ private @ NotNull HashMap <String , SentryLogEventAttributeValue > createAttributes (
102+ final @ NotNull SentryLogParameters params ) {
103+ final @ NotNull HashMap <String , SentryLogEventAttributeValue > attributes = new HashMap <>();
104+ final @ NotNull String origin = params .getOrigin ();
105+ if (!"manual" .equalsIgnoreCase (origin )) {
106+ attributes .put (
107+ "sentry.origin" , new SentryLogEventAttributeValue (SentryAttributeType .STRING , origin ));
108+ }
109+
110+ final @ Nullable SentryAttributes incomingAttributes = params .getAttributes ();
111+
112+ if (incomingAttributes != null ) {
113+ for (SentryAttribute attribute : incomingAttributes .getAttributes ().values ()) {
114+ final @ Nullable Object value = attribute .getValue ();
115+ final @ NotNull SentryAttributeType type =
116+ attribute .getType () == null ? getType (value ) : attribute .getType ();
117+ attributes .put (attribute .getName (), new SentryLogEventAttributeValue (type , value ));
118+ }
119+ }
120+
121+ final @ Nullable SdkVersion sdkVersion = scopes .getOptions ().getSdkVersion ();
122+ if (sdkVersion != null ) {
123+ attributes .put (
124+ "sentry.sdk.name" ,
125+ new SentryLogEventAttributeValue (SentryAttributeType .STRING , sdkVersion .getName ()));
126+ attributes .put (
127+ "sentry.sdk.version" ,
128+ new SentryLogEventAttributeValue (SentryAttributeType .STRING , sdkVersion .getVersion ()));
129+ }
130+
131+ final @ Nullable String environment = scopes .getOptions ().getEnvironment ();
132+ if (environment != null ) {
133+ attributes .put (
134+ "sentry.environment" ,
135+ new SentryLogEventAttributeValue (SentryAttributeType .STRING , environment ));
136+ }
137+
138+ final @ NotNull SentryId scopeReplayId = scopes .getCombinedScopeView ().getReplayId ();
139+ if (!SentryId .EMPTY_ID .equals (scopeReplayId )) {
140+ attributes .put (
141+ "sentry.replay_id" ,
142+ new SentryLogEventAttributeValue (SentryAttributeType .STRING , scopeReplayId .toString ()));
143+ } else {
144+ final @ NotNull SentryId controllerReplayId =
145+ scopes .getOptions ().getReplayController ().getReplayId ();
146+ if (!SentryId .EMPTY_ID .equals (controllerReplayId )) {
147+ attributes .put (
148+ "sentry.replay_id" ,
149+ new SentryLogEventAttributeValue (
150+ SentryAttributeType .STRING , controllerReplayId .toString ()));
151+ attributes .put (
152+ "sentry._internal.replay_is_buffering" ,
153+ new SentryLogEventAttributeValue (SentryAttributeType .BOOLEAN , true ));
154+ }
155+ }
156+
157+ final @ Nullable String release = scopes .getOptions ().getRelease ();
158+ if (release != null ) {
159+ attributes .put (
160+ "sentry.release" , new SentryLogEventAttributeValue (SentryAttributeType .STRING , release ));
161+ }
162+
163+ if (Platform .isJvm ()) {
164+ setServerName (attributes );
165+ }
166+
167+ setUser (attributes );
168+
169+ return attributes ;
170+ }
171+
172+ private void setServerName (
173+ final @ NotNull HashMap <String , SentryLogEventAttributeValue > attributes ) {
174+ final @ NotNull SentryOptions options = scopes .getOptions ();
175+ final @ Nullable String optionsServerName = options .getServerName ();
176+ if (optionsServerName != null ) {
177+ attributes .put (
178+ "server.address" ,
179+ new SentryLogEventAttributeValue (SentryAttributeType .STRING , optionsServerName ));
180+ } else if (options .isAttachServerName ()) {
181+ final @ Nullable String hostname = HostnameCache .getInstance ().getHostname ();
182+ if (hostname != null ) {
183+ attributes .put (
184+ "server.address" ,
185+ new SentryLogEventAttributeValue (SentryAttributeType .STRING , hostname ));
186+ }
187+ }
188+ }
189+
190+ private void setUser (final @ NotNull HashMap <String , SentryLogEventAttributeValue > attributes ) {
191+ final @ Nullable User user = scopes .getCombinedScopeView ().getUser ();
192+ if (user == null ) {
193+ // In case no user is set, we should fallback to the distinct id, known as installation id,
194+ // which is used on Android as default user id
195+ final @ Nullable String id = scopes .getOptions ().getDistinctId ();
196+ if (id != null ) {
197+ attributes .put ("user.id" , new SentryLogEventAttributeValue (SentryAttributeType .STRING , id ));
198+ }
199+ } else {
200+ final @ Nullable String id = user .getId ();
201+ if (id != null ) {
202+ attributes .put ("user.id" , new SentryLogEventAttributeValue (SentryAttributeType .STRING , id ));
203+ }
204+ final @ Nullable String username = user .getUsername ();
205+ if (username != null ) {
206+ attributes .put (
207+ "user.name" , new SentryLogEventAttributeValue (SentryAttributeType .STRING , username ));
208+ }
209+ final @ Nullable String email = user .getEmail ();
210+ if (email != null ) {
211+ attributes .put (
212+ "user.email" , new SentryLogEventAttributeValue (SentryAttributeType .STRING , email ));
213+ }
214+ }
215+ }
216+
217+ private @ NotNull SentryAttributeType getType (final @ Nullable Object arg ) {
218+ if (arg instanceof Boolean ) {
219+ return SentryAttributeType .BOOLEAN ;
220+ }
221+ if (arg instanceof Integer ) {
222+ return SentryAttributeType .INTEGER ;
223+ }
224+ if (arg instanceof Number ) {
225+ return SentryAttributeType .DOUBLE ;
226+ }
227+ return SentryAttributeType .STRING ;
17228 }
18229}
0 commit comments