美文网首页
Sentry-Spring Boot Starter的实现(适用

Sentry-Spring Boot Starter的实现(适用

作者: 天草二十六_简村人 | 来源:发表于2021-09-14 22:28 被阅读0次

    一、背景

    sentry官方已有提供sentry-spring-boot-starter支持spring boot项目,但是存在版本的差异。starter 1.7.30支持spring boot的版本是1.5.x, starter 3.0.0开始则要求你的spring boot版本必须大于2.1.x及以上。
    差异主要是在spring boot的相关类,sentry、sentry-spring和sentry-logback等并没有版本要求,所以你想要使用sentry的高版本jar包,而又无法使用官方的starter。
    本文则是出于此目标,提供一套简易的自定义starter,让你可以引入并支持高版本的sentry等jar包。

    二、总体情况

    想要实现一个starter,必不可少的两块是,首先是配置项,其次是configure类。

    • 配置项:SentryProperties.java
    • configure类:SentryLogbackAppenderAutoConfiguration.java和SentryConfiguration.java

    下面是具体的代码实现。

    三、具体实现

    1、pom.xml

    <!--sentry-->
    <dependency>
        <groupId>io.sentry</groupId>
        <artifactId>sentry-spring</artifactId>
        <version>4.3.0</version>
    </dependency>
    <dependency>
        <groupId>io.sentry</groupId>
        <artifactId>sentry-logback</artifactId>
        <version>4.3.0</version>
    </dependency>
    

    2、配置项

    • application.yml
      应用的版本必须配置在application.yml中,mvn打包的时候替换为pom.xml中project的version值。
    # sentry配置
    sentry:
      # 应用的版本号
      release: @project.version@
    
    • 分布式配置
    # sentry配置
    sentry:
      dsn: http://1be0a59354f241e3a3956e6924d42cc5@192.168.10.109:9000/11
      # 多环境
      environment: dev
    

    3、java代码

    • SentryProperties.java
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
     
    /**
     * sentry.property
     *
     * @author zwp
     */
    @Data
    @Configuration
    @ConfigurationProperties("sentry")
    public class SentryProperties {
        /**
         * Whether to enable sentry.
         */
        private boolean enabled = true;
     
        /**
         * is debug model
         */
        private Boolean debug = false;
        /**
         * dsn
         */
        private String dsn;
        /**
         * The application version that will be sent with each event.
         */
        private String release;
     
        /**
         * The application environment that will be sent with each event.
         */
        private String environment;
     
        /**
         * Tags that will be sent with each event.
         */
        private Map<String, String> tags = new LinkedHashMap<>();
     
    }
    
    • SentryLogbackAppenderAutoConfiguration.java
    import ch.qos.logback.classic.LoggerContext;
    import io.sentry.logback.SentryAppender;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
     
    /**
     * Auto-configures {@link SentryAppender}.
     */
    @Configuration
    @ConditionalOnClass({LoggerContext.class, SentryAppender.class})
    @ConditionalOnProperty(name = "sentry.logging.enabled", havingValue = "true", matchIfMissing = true)
    public class SentryLogbackAppenderAutoConfiguration {
     
        @Bean
        public SentryLogbackInitializer sentryLogbackInitializer(
                final SentryProperties sentryProperties) {
            return new SentryLogbackInitializer(sentryProperties);
        }
    }
    
    • SentryLogbackInitializer.java

    虽然构造函数引入了成员变量sentryProperties,但暂时没用上,待你自己实现。我这里是直接固定了值。
    sentryAppender.setMinimumEventLevel(Level.ERROR);
    sentryAppender.setMinimumBreadcrumbLevel(Level.INFO);

    import ch.qos.logback.classic.Level;
    import ch.qos.logback.classic.Logger;
    import ch.qos.logback.classic.LoggerContext;
    import ch.qos.logback.classic.spi.ILoggingEvent;
    import ch.qos.logback.core.Appender;
    import io.sentry.logback.SentryAppender;
    import io.sentry.util.Objects;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.ApplicationListener;
     
    import java.util.Iterator;
     
    /**
     * Registers {@link SentryAppender} after Spring context gets refreshed.
     */
    class SentryLogbackInitializer implements ApplicationListener {
        private final SentryProperties sentryProperties;
     
        public SentryLogbackInitializer(final SentryProperties sentryProperties) {
            this.sentryProperties = Objects.requireNonNull(sentryProperties, "properties are required");
        }
     
        @Override
        public void onApplicationEvent(final ApplicationEvent event) {
            final Logger rootLogger = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
     
            if (!isSentryAppenderRegistered(rootLogger)) {
                final SentryAppender sentryAppender = new SentryAppender();
                sentryAppender.setName("SENTRY_APPENDER");
                sentryAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
     
                sentryAppender.setMinimumEventLevel(Level.ERROR);
                sentryAppender.setMinimumBreadcrumbLevel(Level.INFO);
                sentryAppender.start();
     
                rootLogger.addAppender(sentryAppender);
            }
        }
     
        private boolean isSentryAppenderRegistered(final Logger logger) {
            final Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
            while (it.hasNext()) {
                final Appender<ILoggingEvent> appender = it.next();
     
                if (appender.getClass().equals(SentryAppender.class)) {
                    return true;
                }
            }
            return false;
        }
    }
    
    • SentryConfiguration.java
    import io.sentry.Sentry;
    import io.sentry.spring.SentryExceptionResolver;
    import io.sentry.util.Objects;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.HandlerExceptionResolver;
     
    import javax.annotation.PostConstruct;
    import java.util.Map;
     
    /**
     * sentry配置初始化.
     *
     */
    @ConditionalOnClass({HandlerExceptionResolver.class, SentryExceptionResolver.class})
    @ConditionalOnWebApplication
    @ConditionalOnProperty(name = "sentry.enabled", havingValue = "true", matchIfMissing = true)
    @Configuration
    public class SentryConfiguration {
        private final SentryProperties sentryProperties;
     
        public SentryConfiguration(final SentryProperties sentryProperties) {
            this.sentryProperties = Objects.requireNonNull(sentryProperties, "properties are required");
        }
     
        @PostConstruct
        public void init() {
            if (StringUtils.isEmpty(sentryProperties.getDsn())) {
                return;
            }
     
            Sentry.init(options -> {
                options.setDsn(sentryProperties.getDsn());
                options.setDebug(sentryProperties.getDebug() != null ? sentryProperties.getDebug() : false);
     
                if (StringUtils.isNotEmpty(sentryProperties.getRelease())) {
                    options.setRelease(sentryProperties.getRelease());
                }
                if (StringUtils.isNotEmpty(sentryProperties.getEnvironment())) {
                    options.setEnvironment(sentryProperties.getEnvironment());
                }
     
                String serverIp = System.getProperty("server.ip");
                if (StringUtils.isNotEmpty(serverIp)) {
                    options.setTag("serverIp", serverIp);
                }
     
                if (sentryProperties.getTags() != null && !sentryProperties.getTags().isEmpty()) {
                    for (Map.Entry<String, String> tag : sentryProperties.getTags().entrySet()) {
                        options.setTag(tag.getKey(), tag.getValue());
                    }
                }
     
            });
        }
    }
    

    相关文章

      网友评论

          本文标题:Sentry-Spring Boot Starter的实现(适用

          本文链接:https://www.haomeiwen.com/subject/rvocgltx.html