77import io .sentry .IScopes ;
88import io .sentry .ISentryLifecycleToken ;
99import io .sentry .MonitorConfig ;
10- import io .sentry .MonitorSchedule ;
11- import io .sentry .MonitorScheduleUnit ;
1210import io .sentry .ScopesAdapter ;
1311import io .sentry .SentryLevel ;
1412import io .sentry .protocol .SentryId ;
1513import io .sentry .time .Stopwatch ;
14+ import io .sentry .util .MonitorConfigUtils ;
1615import io .sentry .util .Objects ;
1716import io .sentry .util .TracingUtils ;
1817import java .lang .reflect .Method ;
1918import java .time .Duration ;
20- import java .util .HashMap ;
21- import java .util .Locale ;
22- import java .util .Map ;
2319import java .util .Set ;
2420import java .util .concurrent .TimeUnit ;
2521import org .aopalliance .intercept .MethodInterceptor ;
3329import org .springframework .core .annotation .AnnotationUtils ;
3430import org .springframework .scheduling .annotation .Scheduled ;
3531import org .springframework .util .ObjectUtils ;
36- import org .springframework .util .StringUtils ;
3732import org .springframework .util .StringValueResolver ;
3833
3934/**
4338@ ApiStatus .Internal
4439@ Open
4540public class SentryCheckInAdvice implements MethodInterceptor , EmbeddedValueResolverAware {
46- private static final @ NotNull Map <String , String > CRON_MACROS = new HashMap <>();
47-
48- static {
49- CRON_MACROS .put ("@yearly" , "0 0 1 1 *" );
50- CRON_MACROS .put ("@annually" , "0 0 1 1 *" );
51- CRON_MACROS .put ("@monthly" , "0 0 1 * *" );
52- CRON_MACROS .put ("@weekly" , "0 0 * * 0" );
53- CRON_MACROS .put ("@daily" , "0 0 * * *" );
54- CRON_MACROS .put ("@midnight" , "0 0 * * *" );
55- CRON_MACROS .put ("@hourly" , "0 * * * *" );
56- }
57-
5841 private final @ NotNull IScopes scopes ;
5942
6043 private @ Nullable StringValueResolver resolver ;
@@ -149,40 +132,21 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl
149132 return null ;
150133 }
151134 final @ NotNull Scheduled scheduled = schedules .iterator ().next ();
135+ // timeUnit only exists from Spring 5.3.10, so read it as an attribute
136+ final @ Nullable Object timeUnitAttribute =
137+ AnnotationUtils .getAnnotationAttributes (scheduled ).get ("timeUnit" );
138+ final @ NotNull TimeUnit timeUnit =
139+ timeUnitAttribute instanceof TimeUnit
140+ ? (TimeUnit ) timeUnitAttribute
141+ : TimeUnit .MILLISECONDS ;
152142 final @ Nullable String cron = resolve (scheduled .cron ());
153- final @ Nullable Long fixedRate =
154- periodMillis (scheduled , scheduled .fixedRate (), scheduled .fixedRateString ());
155- final @ Nullable Long fixedDelay =
156- periodMillis (scheduled , scheduled .fixedDelay (), scheduled .fixedDelayString ());
157- final boolean hasCron = cron != null && !cron .isEmpty ();
158-
159- if (hasCron && cron != null && fixedRate == null && fixedDelay == null ) {
160- final @ Nullable String crontab = toCrontab (cron );
161- if (crontab == null ) {
162- return null ;
163- }
164- final @ NotNull MonitorConfig config = new MonitorConfig (MonitorSchedule .crontab (crontab ));
165- final @ Nullable String zone = resolve (scheduled .zone ());
166- if (zone != null && !zone .isEmpty ()) {
167- config .setTimezone (zone );
168- }
169- return config ;
170- }
171- final @ Nullable Long period = fixedRate != null ? fixedRate : fixedDelay ;
172- if (!hasCron && period != null && (fixedRate == null || fixedDelay == null )) {
173- final long millis = period ;
174- final long minuteMillis = TimeUnit .MINUTES .toMillis (1 );
175- if (millis < minuteMillis || millis % minuteMillis != 0 ) {
176- return null ;
177- }
178- final long minutes = millis / minuteMillis ;
179- if (minutes > Integer .MAX_VALUE ) {
180- return null ;
181- }
182- return new MonitorConfig (
183- MonitorSchedule .interval ((int ) minutes , MonitorScheduleUnit .MINUTE ));
184- }
185- return null ;
143+ final @ Nullable String zone =
144+ cron != null && !cron .isEmpty () ? resolve (scheduled .zone ()) : null ;
145+ return MonitorConfigUtils .fromSchedule (
146+ cron ,
147+ zone ,
148+ periodMillis (scheduled .fixedRate (), scheduled .fixedRateString (), timeUnit ),
149+ periodMillis (scheduled .fixedDelay (), scheduled .fixedDelayString (), timeUnit ));
186150 } catch (RuntimeException e ) {
187151 scopes
188152 .getOptions ()
@@ -196,14 +160,7 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl
196160 }
197161
198162 private @ Nullable Long periodMillis (
199- final @ NotNull Scheduled scheduled , final long value , final @ NotNull String valueString ) {
200- // timeUnit only exists from Spring 5.3.10, so read it as an attribute
201- final @ Nullable Object timeUnitAttribute =
202- AnnotationUtils .getAnnotationAttributes (scheduled ).get ("timeUnit" );
203- final @ NotNull TimeUnit timeUnit =
204- timeUnitAttribute instanceof TimeUnit
205- ? (TimeUnit ) timeUnitAttribute
206- : TimeUnit .MILLISECONDS ;
163+ final long value , final @ NotNull String valueString , final @ NotNull TimeUnit timeUnit ) {
207164 if (value >= 0 ) {
208165 return timeUnit .toMillis (value );
209166 }
@@ -218,34 +175,6 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl
218175 return timeUnit .toMillis (Long .parseLong (trimmed ));
219176 }
220177
221- /**
222- * Converts a Spring cron expression (6 fields, seconds first) to a 5 field crontab. Returns null
223- * unless the seconds field is a single fixed number, since crontab cannot express sub-minute
224- * schedules.
225- */
226- private static @ Nullable String toCrontab (final @ NotNull String cron ) {
227- final @ NotNull String trimmed = cron .trim ();
228- if (Scheduled .CRON_DISABLED .equals (trimmed )) {
229- return null ;
230- }
231- if (trimmed .startsWith ("@" )) {
232- return CRON_MACROS .get (trimmed .toLowerCase (Locale .ROOT ));
233- }
234- final @ NotNull String [] fields = StringUtils .tokenizeToStringArray (trimmed , " \t " );
235- if (fields .length != 6 || !fields [0 ].matches ("\\ d{1,2}" )) {
236- return null ;
237- }
238- final @ NotNull StringBuilder crontab = new StringBuilder ();
239- for (int i = 1 ; i < fields .length ; i ++) {
240- if (i > 1 ) {
241- crontab .append (' ' );
242- }
243- // Spring treats '?' like '*'
244- crontab .append ("?" .equals (fields [i ]) ? "*" : fields [i ]);
245- }
246- return crontab .toString ();
247- }
248-
249178 private @ Nullable String resolve (final @ NotNull String value ) {
250179 if (resolver == null || value .isEmpty ()) {
251180 return value ;
0 commit comments