├── .editconfig ├── .gitignore ├── README.md ├── doc ├── 0.all.md ├── api.md ├── db.md ├── dubbo.md ├── http.md ├── img │ ├── alarm-1.png │ ├── hot.png │ ├── overview.png │ ├── rocketmq-monitor.png │ ├── screenshot.png │ ├── screenshot2.png │ ├── sea-monitor-arch-1.png │ ├── sea-monitor-arch-2.png │ ├── spy_pay_alipay.jpeg │ ├── spy_pay_all.jpeg │ └── spy_pay_wx.jpeg ├── jvm.md ├── log.md ├── mybatis.md ├── project.md ├── redis.md ├── rocketmq.md ├── system.md ├── threadPool.md ├── tomcat.md └── trace.md ├── pom.xml ├── sea-monitor-boot-starter-demo ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── seaframework │ │ └── monitor │ │ └── boot │ │ └── demo │ │ └── SeaMonitorApplication.java │ └── resources │ ├── application-local.yml │ ├── application.yml │ └── logback-spring.xml ├── sea-monitor-boot-starter ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── seaframework │ │ └── monitor │ │ └── boot │ │ └── autoconfigure │ │ ├── SeaMonitorAutoConfigure.java │ │ ├── SeaMonitorProperties.java │ │ └── listener │ │ └── SpringApplicationStartListener.java │ └── resources │ ├── META-INF │ ├── additional-spring-configuration-metadata.json │ └── spring.factories │ └── README.md ├── sea-monitor-web-demo ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── seaframework │ │ └── monitor │ │ └── demo │ │ ├── controller │ │ ├── AbstractController.java │ │ ├── AbstractTestController.java │ │ ├── LogController.java │ │ └── UserController.java │ │ ├── custom │ │ └── MyThreadPoolStatusExtension.java │ │ ├── listener │ │ └── ApplicationInitListener.java │ │ ├── package-info.java │ │ ├── service │ │ ├── UserService.java │ │ └── impl │ │ │ └── UserServiceImpl.java │ │ └── task │ │ └── UserJob.java │ ├── resources │ ├── META-INF │ │ └── services │ │ │ └── com.github.seaframework.monitor.heartbeat.StatusExtension │ ├── logback.xml │ ├── sea.monitor.properties │ └── spring │ │ ├── dubbo │ │ └── spring-dubbo.xml │ │ ├── spring-all.xml │ │ └── spring-mvc.xml │ └── webapp │ ├── WEB-INF │ └── web.xml │ └── index.jsp └── sea-monitor ├── file └── 501.txt ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── github │ │ └── seaframework │ │ └── monitor │ │ ├── SeaMonitor.java │ │ ├── annotation │ │ └── SeaMonitorTrace.java │ │ ├── aop │ │ └── SeaMonitorAspect.java │ │ ├── common │ │ ├── MonitorCommon.java │ │ ├── MonitorConst.java │ │ └── TagConst.java │ │ ├── druid │ │ └── DruidMonitorFilter.java │ │ ├── dto │ │ ├── BaseMonitorDTO.java │ │ └── MetricDTO.java │ │ ├── dubbo │ │ ├── AbstractDubboExceptionMonitorFilter.java │ │ ├── alibaba │ │ │ └── DubboExceptionMonitorFilter.java │ │ ├── apache │ │ │ └── DubboExceptionMonitorFilter.java │ │ └── package-info.java │ │ ├── enums │ │ ├── CounterEnum.java │ │ └── MonitorModeEnum.java │ │ ├── filter │ │ └── SeaMonitorFilter.java │ │ ├── heartbeat │ │ ├── AbstractCollector.java │ │ ├── HeartbeatManager.java │ │ ├── StatusExtension.java │ │ ├── StatusExtensionRegister.java │ │ ├── biz │ │ │ ├── BizDataStats.java │ │ │ ├── BizDataStatsCollector.java │ │ │ └── package-info.java │ │ ├── data │ │ │ ├── DataStats.java │ │ │ └── DataStatsCollector.java │ │ ├── datasource │ │ │ ├── DataSourceCollector.java │ │ │ ├── DatabaseParserHelper.java │ │ │ ├── druid │ │ │ │ ├── DruidInfoCollector.java │ │ │ │ └── DruidMonitorInfo.java │ │ │ └── hikari │ │ │ │ ├── HikariInfoCollector.java │ │ │ │ └── HikariMonitorInfo.java │ │ ├── dubbo │ │ │ ├── AbstractDubboThreadPoolHeartbeat.java │ │ │ ├── DubboLegacyThreadPoolHeartbeat.java │ │ │ └── DubboThreadPoolHeartbeat.java │ │ ├── http │ │ │ ├── HttpStats.java │ │ │ └── HttpStatsCollector.java │ │ ├── impl │ │ │ └── DefaultHeartbeatManager.java │ │ ├── jvm │ │ │ ├── ClassLoadingInfoCollector.java │ │ │ ├── JvmInfoCollector.java │ │ │ ├── MemoryInformation.java │ │ │ └── ThreadInfoCollector.java │ │ ├── redis │ │ │ ├── AbstractRedisStatsCollector.java │ │ │ └── RedisMonitorInfo.java │ │ ├── sys │ │ │ └── SysAliveCollector.java │ │ └── tomcat │ │ │ ├── TomcatHttpStatsCollector.java │ │ │ └── TomcatThreadPoolStatsCollector.java │ │ ├── log4j │ │ ├── Log4j2Appender.java │ │ └── SeaMonitorAppender.java │ │ ├── logback │ │ └── SeaMonitorAppender.java │ │ ├── message │ │ ├── MessageProducer.java │ │ ├── disruptor │ │ │ ├── DefaultMessageProducer.java │ │ │ ├── MessageConsumerHandler.java │ │ │ ├── MessageEvent.java │ │ │ └── MessageEventFactory.java │ │ └── simple │ │ │ ├── SimpleConsumerTask.java │ │ │ └── SimpleMessageProducer.java │ │ ├── mybatis │ │ └── MybatisMonitorInterceptor.java │ │ ├── samplers │ │ ├── PercentageBasedSampler.java │ │ ├── Sampler.java │ │ ├── SamplerProperties.java │ │ └── SamplingStatus.java │ │ ├── trace │ │ ├── TraceExtension.java │ │ └── impl │ │ │ └── DefaultTraceExtension.java │ │ ├── util │ │ ├── JMXUtil.java │ │ ├── MonitorPushScheduler.java │ │ ├── MonitorSendUtil.java │ │ ├── TagUtil.java │ │ ├── ThreadPoolUtil.java │ │ └── TraceUtil.java │ │ └── vo │ │ └── ThreadPoolStatus.java └── resources │ ├── META-INF │ └── services │ │ └── com.github.seaframework.monitor.trace.TraceExtension │ └── README.md └── test ├── java └── com │ └── github │ └── spy │ └── sea │ └── monitor │ └── SeaMonitorTest.java └── resources ├── logback.xml └── sea.monitor.properties /.editconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /src/main/resources/rebel.xml 2 | /.idea 3 | /target 4 | ~/log/ 5 | vs-boss.iml 6 | *.iml 7 | vs-boss-web/${catalina.home}/ 8 | vs-boss-web/disconf/download 9 | *.class 10 | /bin/* 11 | 12 | 13 | target/ 14 | !.mvn/wrapper/maven-wrapper.jar 15 | 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | 23 | .idea 24 | *.iws 25 | *.iml 26 | *.ipr 27 | 28 | nbproject/private/ 29 | build/ 30 | nbbuild/ 31 | dist/ 32 | nbdist/ 33 | .nb-gradle/ 34 | 35 | 36 | #-----custom----- 37 | 38 | .DS_Store 39 | node_modules/ 40 | dist/ 41 | npm-debug.log 42 | test/unit/coverage 43 | test/e2e/reports 44 | selenium-debug.log 45 | 46 | .classpath 47 | .project 48 | .settings/ 49 | target/ 50 | out/ 51 | output/ 52 | 53 | .idea/ 54 | *.iml 55 | logging.path_IS_UNDEFINED/ 56 | nohup.out 57 | 58 | disconf/ 59 | disconf/download 60 | deps_tree.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sea-monitor 2 | 3 | ## Stargazers over time 4 | 5 | [![Stargazers over time](https://starchart.cc/seaframework/sea-monitor-all.svg)](https://starchart.cc/seaframework/sea-monitor-all) 6 | 7 | > N9E java sdk,采集应用数据上报N9E collector 或transfer。 8 | 9 | ## Overview 10 | 11 | ### 后端截图 12 | 13 | ![](doc/img/overview.png) 14 | 15 | ### 报警截图 16 | 17 | ![](doc/img/screenshot.png) 18 | ![](doc/img/screenshot2.png) 19 | 20 | ## 架构 21 | > sea-monitor默认情况下以SDK形式嵌入到应用,方便研发人员使用; 22 | > 23 | > 支持PUSH和Pull两种模式,push模式是异步上报到N9E-collector,pull模式需要自己采集日志 24 | 25 | ### push方式(默认) 26 | ![](doc/img/sea-monitor-arch-1.png) 27 | 28 | ### Pull方式(支持) 29 | ![](doc/img/sea-monitor-arch-2.png) 30 | 31 | 32 | ## 原理 33 | 34 | - 应用启动后,初始化SeaMonitor类,启动消息发送线程 35 | - 当调用SeaMonitor API时,数据点即Metrics,会放入队列,消息发送线程会周期性的将数据发送至远端 36 | - 在N9E monapi端定义告警策略,集成钉钉通知 37 | 38 | ## 工程结构 39 | ```` 40 | ├── sea-monitor // 监控SDK 41 | ├── sea-monitor-boot-starter // spring-boot工程集成 42 | ├── sea-monitor-boot-starter-demo // spring-boot工程示例 43 | └── sea-monitor-web-demo // 常规spring-web工程示例 44 | ```` 45 | 46 | ## Doc 47 | 48 | 支持的中间件以及API 49 | 50 | - ![](doc/img/hot.png)[Sea-Monitor SDK API](doc/api.md) 51 | - ![](doc/img/hot.png)[spring & spring-boot 等Java工程集成](doc/project.md) 52 | - ![](doc/img/hot.png)[直达异常链路](doc/trace.md) 53 | - [系统(全局)级监控](doc/system.md) 54 | - [JVM监控](doc/jvm.md) 55 | - [Tomcat监控](doc/tomcat.md) 56 | - [Dubbo监控](doc/dubbo.md) 57 | - [DB连接池监控](doc/db.md) 58 | - [Http异常监控](doc/http.md) 59 | - [SQL监控](doc/mybatis.md) 60 | - [Redis连接池监控](doc/redis.md) 61 | - [线程池监控](doc/threadPool.md) 62 | - [RocketMQ-Broker监控](doc/rocketmq.md) 63 | 64 | 65 | ## API 66 | 67 | 更多请参考[这里](doc/api.md) 68 | ### 单个指标 69 | 70 | ```` 71 | MetricDTO metricDTO = new MetricDTO(); 72 | metricDTO.setMetric(MetricEnum.HTTP_REQUEST_ERROR.getKey()); 73 | metricDTO.setValue(1); 74 | metricDTO.setErrorFlag(true); 75 | metricDTO.setTraceIdFlag(true); 76 | SeaMonitor.logMetric(metricDTO); 77 | ```` 78 | 79 | ### 统计指标 80 | 81 | ```` 82 | SeaMonitor.logCount(MetricEnum.HTTP_REQUEST_ERROR_COUNT.getKey()); 83 | ```` 84 | 85 | ### SPI扩展指标 86 | > 适用于定制化周期性指标上报,统计周期1min 87 | 88 | - 在`META-INF/service/`目录下新建文件`com.github.seaframework.monitor.heartbeat.StatusExtension` 89 | - `实现接口com.github.seaframework.monitor.heartbeat.StatusExtension` 90 | - `META-INF/service/com.github.seaframework.monitor.heartbeat.StatusExtension`文件中存放对应的实现类即可 91 | 92 | ## 参考资料 93 | 94 | - SDK的实现参考了CAT-SDK 95 | - 感谢N9E团队的支持 96 | 97 | ## 最后 98 | 99 | > 您的支持是我最大的动力 100 | 101 | drawing 102 | 103 | -------------------------------------------------------------------------------- /doc/0.all.md: -------------------------------------------------------------------------------- 1 | # sea-monitor 集成 2 | 3 | > 这里罗列了支持的中间件以及API 4 | 5 | ## 支持列表 6 | 7 | - [spring & spring-boot 工程支持](project.md) 8 | - [JVM监控](jvm.md) 9 | - [Tomcat监控](tomcat.md) 10 | - [Dubbo连接池监控](dubbo.md) 11 | - [DB连接池监控](db.md) 12 | - [Http异常监控](http.md) 13 | - [SQL监控](mybatis.md) 14 | - [Redis连接池监控](redis.md) 15 | - [线程池监控](threadPool.md) 16 | - [Sea-Monnitor API](api.md) 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /doc/api.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | ## 单个指标 4 | 5 | ```` 6 | MetricDTO metricDTO = new MetricDTO(); 7 | metricDTO.setMetric(MetricEnum.HTTP_REQUEST_ERROR.getKey()); 8 | metricDTO.setValue(1); 9 | metricDTO.setErrorFlag(true); 10 | metricDTO.setTraceIdFlag(true); 11 | SeaMonitor.logMetric(metricDTO); 12 | ```` 13 | 14 | ## 统计指标 15 | 16 | ```` 17 | SeaMonitor.logCount(MetricEnum.HTTP_REQUEST_ERROR_COUNT.getKey()); 18 | ```` 19 | 20 | ## SPI扩展指标 21 | > 适用于定制化周期性指标上报,统计周期1min 22 | 23 | ```` 24 | META-INF/service/com.github.seaframework.monitor.heartbeat.StatusExtension 25 | 实现接口com.github.seaframework.monitor.heartbeat.StatusExtension 26 | ```` 27 | 28 | ```` 29 | public Map getProperties() 30 | ```` 31 | - 接口map支持普通key value 32 | - map支持返回value是List 33 | 34 | 35 | 示例 36 | 37 | ```` 38 | @Slf4j 39 | public class UserThreadPoolStatusExtension implements StatusExtension { 40 | private static final String PREFIX = "user.thread.pool"; 41 | @Override 42 | public String getDescription() { 43 | return PREFIX; 44 | } 45 | @Override 46 | public String getId() { 47 | return PREFIX; 48 | } 49 | @Override 50 | public Map getProperties() { 51 | Map map = new HashMap<>(); 52 | Map poolExecutorMap = ThreadPoolExecutorUtil.getInstance(); 53 | if (MapUtil.isEmpty(poolExecutorMap)) { 54 | return map; 55 | } 56 | poolExecutorMap.forEach((key, value) -> { 57 | ThreadPoolStatus status = ThreadPoolUtil.getStatus(value); 58 | map.put(PREFIX + ".max", status.getMax()); 59 | map.put(PREFIX + ".core", status.getCore()); 60 | map.put(PREFIX + ".largest", status.getLargest()); 61 | map.put(PREFIX + ".active", status.getActive()); 62 | map.put(PREFIX + ".task", status.getTask()); 63 | map.put(PREFIX + ".active.percent", status.getActivePercent()); 64 | }); 65 | return map; 66 | } 67 | } 68 | ```` -------------------------------------------------------------------------------- /doc/db.md: -------------------------------------------------------------------------------- 1 | ## DB连接池监控 2 | 3 | 4 | ## 指标 5 | 6 | |指标|描述| 7 | |----|----| 8 | |database.thread.pool.idle| 空闲连接数 | 9 | |database.thread.pool.busy| 当前活跃连接数| 10 | |database.thread.pool.total| 连接池总数 | 11 | |database.thread.pool.busy.percent| 连接池使用率| 12 | 13 | ## 配置 14 | 15 | - druid 16 | - hikari 17 | 18 | 无需配置,自动探测 19 | 20 | -------------------------------------------------------------------------------- /doc/dubbo.md: -------------------------------------------------------------------------------- 1 | # Dubbo监控 2 | 3 | ## 指标 4 | |指标|描述| 5 | |----|----| 6 | |dubbo.exception.biz.count| 业务异常数 | 7 | |dubbo.exception.forbidden.count| forbidden异常数 | 8 | |dubbo.exception.network.count| network异常数| 9 | |dubbo.exception.serialization.count| 序列化异常数| 10 | |dubbo.exception.timeout.count| timeout异常数| 11 | |dubbo.exception.unknown.count| unkown异常数| 12 | |dubbo.thread.pool.active| dubbo线程池活跃数| 13 | |dubbo.thread.pool.active.percent| dubbo线程池使用率 | 14 | |dubbo.thread.pool.core| dubbo线程池核心线程数 | 15 | |dubbo.thread.pool.max| dubbo线程池最大数 | 16 | |dubbo.thread.pool.task| dubbo线程池任务执行数 | 17 | |dubbo.cost| dubbo服务耗时(超10s上报)| 18 | - ![](img/hot.png)当线程池使用率超过0.9时会自动dump 线程堆栈,目录`${user.home}/logs` 19 | 20 | ## 集成 21 | ### alibaba dubbo (2.7之前) 22 | 23 | ```` 24 | META-INF/dubbo/com.alibaba.dubbo.rpc.Filter 25 | 26 | dubboExceptionMonitorFilter=com.github.seaframework.monitor.dubbo.alibaba.DubboExceptionMonitorFilter 27 | 28 | ```` 29 | 30 | ### apache dubbo (2.7之后) 31 | 32 | ```` 33 | META-INF/dubbo/org.apache.dubbo.rpc.Filter 34 | 35 | dubboExceptionMonitorFilter=com.github.seaframework.monitor.dubbo.apache.DubboExceptionMonitorFilter 36 | ```` 37 | 38 | 39 | ### 配置 dubbo filter 40 | 41 | xml 42 | 43 | ```` 44 | 45 | 46 | ```` 47 | 48 | yml 49 | 50 | ```` 51 | dubbo.provider.filter= default,dubboExceptionMonitorFilter 52 | dubbo.consumer.filter=default,dubboExceptionMonitorFilter 53 | 54 | ```` -------------------------------------------------------------------------------- /doc/http.md: -------------------------------------------------------------------------------- 1 | # Http监控 2 | • 服务器内部异常 3 | • 长耗时(超过30s) 4 | 5 | 6 | 7 | ## 指标 8 | 9 | |指标|描述| 10 | |----|----| 11 | |http.500.count| 服务器未捕获的异常| 12 | |http.request.cost.time|请求耗时,超过30s| 13 | 14 | 15 | ## 配置 16 | 17 | - 非spring-boot工程配置参考web.xml中Filter内容 18 | - spring-boot工程无需配置 -------------------------------------------------------------------------------- /doc/img/alarm-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/alarm-1.png -------------------------------------------------------------------------------- /doc/img/hot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/hot.png -------------------------------------------------------------------------------- /doc/img/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/overview.png -------------------------------------------------------------------------------- /doc/img/rocketmq-monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/rocketmq-monitor.png -------------------------------------------------------------------------------- /doc/img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/screenshot.png -------------------------------------------------------------------------------- /doc/img/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/screenshot2.png -------------------------------------------------------------------------------- /doc/img/sea-monitor-arch-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/sea-monitor-arch-1.png -------------------------------------------------------------------------------- /doc/img/sea-monitor-arch-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/sea-monitor-arch-2.png -------------------------------------------------------------------------------- /doc/img/spy_pay_alipay.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/spy_pay_alipay.jpeg -------------------------------------------------------------------------------- /doc/img/spy_pay_all.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/spy_pay_all.jpeg -------------------------------------------------------------------------------- /doc/img/spy_pay_wx.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/doc/img/spy_pay_wx.jpeg -------------------------------------------------------------------------------- /doc/jvm.md: -------------------------------------------------------------------------------- 1 | # JVM监控 2 | 3 | ## 指标 4 | 5 | |指标|描述| 6 | |----|----| 7 | |jvm.classloading.loaded.count| 当前类加载数| 8 | |jvm.classloading.totalloaded.count| 类加载总数 | 9 | |jvm.classloading.unloaded.count| 类卸载总数| 10 | |jvm.fullgc.count| fullgc次数 | 11 | |jvm.fullgc.time| fullgc时间| 12 | |jvm.gc.count| gc次数 | 13 | |jvm.gc.time|gc时间 | 14 | |jvm.memory.codecache.used|codecache使用内存 | 15 | |jvm.memory.codecache.used.percent| codecache内存使用率| 16 | |jvm.memory.eden.used| eden内存大小 | 17 | |jvm.memory.eden.used.percent|eden内存使用率 | 18 | |jvm.memory.metaspace.used| metaspace 内存大小 | 19 | |jvm.memory.metaspace.used.percent| metaspace使用率 | 20 | |jvm.memory.nonheap.used| 非堆内存大小 | 21 | |jvm.memory.nonheap.used.percent|非堆内存使用率 | 22 | |jvm.memory.oldgen.used| 老年代内存大小 | 23 | |jvm.memory.oldgen.used.percent| 老年代内存使用率 | 24 | |jvm.memory.oldgen.used.percent.after.fullgc| fullgc后老年代内存使用率 | 25 | |jvm.memory.perm.used| perm内存大小| 26 | |jvm.memory.perm.used.percent| perm内存使用率 | 27 | |jvm.memory.survivor.used| survivor内存大小 | 28 | |jvm.memory.survivor.used.percent| survivor内存使用率 | 29 | |jvm.memory.used| jvm内存使用大小 | 30 | |jvm.memory.used.percent| jvm内存使用率 | 31 | |jvm.nio.directbuffer.used| nio directbuffer使用内存大小 | 32 | |jvm.nio.mapped.used| nio mapped使用内存大小 | 33 | |jvm.thread.blocked.count| blocked线程数 | 34 | |jvm.thread.count| jvm中线程数 | 35 | |jvm.thread.daemon.count| jvm中daemon线程数| 36 | |jvm.thread.deadlock.count| jvm中死锁线程数 | 37 | |jvm.thread.http.count| jvm中http线程数 | 38 | |jvm.thread.new.count| jvm新建线程数| 39 | |jvm.thread.runnable.count| jvm中运行中的线程数 | 40 | |jvm.thread.terminated.count| 结束的线程数| 41 | |jvm.thread.time_waiting.count| time_waiting状态的线程数| 42 | |jvm.thread.totalstarted.count| jvm总共启动线程数 | 43 | |jvm.thread.waiting.count| wating状态的线程数 | 44 | |jvm.younggc.count| younggc次数| 45 | |jvm.younggc.meantime| younggc持续时间| 46 | |jvm.younggc.time| younggc时间| 47 | 48 | ## 配置 49 | 50 | 无需配置,自动探测 51 | -------------------------------------------------------------------------------- /doc/log.md: -------------------------------------------------------------------------------- 1 | # Log 2 | 3 | ## Log4j 4 | 5 | ## Logback 6 | 7 | 用于统计通过error级别的错误量 8 | logback.xml 9 | 10 | ```` 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ```` -------------------------------------------------------------------------------- /doc/mybatis.md: -------------------------------------------------------------------------------- 1 | # SQL监控 2 | 3 | ## 指标 4 | 5 | |指标|描述| 6 | |----|----| 7 | |db.sql.error| sql执行异常上报| 8 | |db.sql.error.count|一分钟中出错数| 9 | |db.sql.large.record.error|返回记录数超5000上报| 10 | |db.sql.cost|超5s的sql上报| 11 | 12 | ## 配置 13 | 14 | ```` 15 | com.github.seaframework.monitor.mybatis.MybatisMonitorInterceptor 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ```` 27 | 28 | `plugins`属性添加`com.github.seaframework.monitor.mybatis.MybatisMonitorInterceptor` -------------------------------------------------------------------------------- /doc/project.md: -------------------------------------------------------------------------------- 1 | # 工程集成 2 | 3 | ## spring-boot类工程 4 | 5 | pom.xml 6 | 7 | ```` 8 | 9 | 10 | 1.1.0 11 | 12 | 13 | 14 | com.github.seaframework 15 | sea-monitor-boot-starter 16 | ${sea.monitor.version} 17 | 18 | 19 | ```` 20 | 21 | application.yml 22 | 23 | ```` 24 | sea: 25 | # 区域 26 | region: default 27 | monitor: 28 | # 需要手动开启 29 | enabled: true 30 | # 应用名称 31 | endpoint: user 32 | uri: http://172.17.8.105:2059/api/collector/push 33 | # log mode 34 | # 0 report to remote server (by default) 35 | # 1 log to local log file 36 | mode: 0 37 | sample: 38 | # 采样率 39 | percent: 100 40 | consumer: 41 | count: 1 42 | send: 43 | element: 44 | max: 45 | # 发送的最大元素个数 46 | count: 200 47 | # 发送间隔,单位秒 48 | period: 49 | time: 20 50 | ```` 51 | 52 | 完整示例,请参考`sea-monitor-all/sea-monitor-boot-starer-demo`工程 53 | 54 | 55 | ## 非spring-boot类工程 56 | 57 | ### pom.xml 58 | 59 | ```` 60 | 61 | 62 | 1.0.0 63 | 64 | 65 | 66 | 67 | com.github.seaframework 68 | sea-monitor 69 | ${sea.monitor.version} 70 | 71 | 72 | ```` 73 | 74 | ### sea.monitor.properties 75 | 76 | 在工程目录resource放sea.monitor.properties文件,内容如下 77 | 78 | ```` 79 | # 80 | # 区域 81 | sea.region=default 82 | # sea monitor enable or not 83 | sea.monitor.enabled=true 84 | # application name 85 | sea.monitor.endpoint=user // 修改成当前系统名称 86 | # log mode 87 | # 0 report to remote server (by default) 88 | # 1 log to local log file 89 | sea.monitor.mode=0 90 | # sea monitor uri 91 | sea.monitor.uri=http://127.0.0.1:2058/api/collector/push 92 | # 采样率 93 | sea.monitor.sample.percent=100 94 | # 消费者个数,不建议修改 95 | sea.monitor.consumer.count=1 96 | # 发送的最大元素个数 97 | sea.monitor.send.element.max.count=200 98 | # 发送间隔,单位秒 99 | sea.monitor.send.period.time=20 100 | ```` 101 | 102 | 完整示例,请参考`sea-monitor-all/sea-monitor-web-demo`工程 103 | 104 | ### 配置Filter 105 | 106 | WEB-INF/web.xml 107 | 108 | ```` 109 | 110 | sea-monitor 111 | com.github.seaframework.monitor.filter.SeaMonitorFilter 112 | 113 | 114 | sea-monitor 115 | /* 116 | 117 | ```` 118 | 119 | `/*`这类拦截了所有请求,其实吧,像`/api/*`这种才是最好的,你开心就好 120 | 121 | 122 | ### spring AOP (可选) 123 | 124 | 使用@SeaMonitorTrace 注解 125 | 126 | metric:指标名称 127 | 128 | ```` 129 | 130 | 131 | @Override 132 | @SeaMonitorTrace(metric = "user.add.exception") 133 | public void addException() { 134 | throw new NullPointerException(); 135 | } 136 | ```` 137 | 138 | 139 | 140 | ## 手动集成 141 | 142 | > 适用于任意Java项目工程,手写的才是最好的!不要相信轮子! 143 | > 144 | > 145 | 146 | ```` 147 | String region = ""; 148 | String enabled = ""; 149 | String endpoint = ""; 150 | String uri = ""; 151 | 152 | Configuration cfg = ConfigurationFactory.getInstance(); 153 | cfg.putString(MonitorConst.CONFIG_KEY_REGION, region); 154 | cfg.putString(MonitorConst.CONFIG_KEY_ENABLED, enabled); 155 | cfg.putString(MonitorConst.CONFIG_KEY_ENDPOINT, endpoint); 156 | cfg.putString(MonitorConst.CONFIG_KEY_URI, uri); 157 | 158 | if (BooleanUtil.isTrue(enabled)) { 159 | SeaMonitor.enable(); 160 | new Thread() { 161 | @Override 162 | public void run() { 163 | SeaMonitor.initialize(); 164 | } 165 | }.start(); 166 | } else { 167 | SeaMonitor.disable(); 168 | } 169 | ```` 170 | 171 | -------------------------------------------------------------------------------- /doc/redis.md: -------------------------------------------------------------------------------- 1 | ## Redis连接池监控 2 | 3 | ## 指标 4 | 5 | |指标|描述| 6 | |----|----| 7 | |redis.pool.active.count|连接池活跃数| 8 | |redis.pool.idle.count| 连接池空闲数 | 9 | |redis.pool.waiter.count| 连接池等待数| 10 | |redis.pool.total.count| 连接池总数| 11 | |redis.pool.active.percent|连接池使用率 | 12 | 13 | ## 集成 14 | 手动集成 15 | 16 | ## 示例 17 | 18 | ```` 19 | META-INF/service/com.github.seaframework.monitor.heartbeat.StatusExtension 20 | ```` 21 | 22 | ```` 23 | @Slf4j 24 | public class RedisStatsCollector implements StatusExtension { 25 | @Override 26 | public String getDescription() { 27 | return getId(); 28 | } 29 | @Override 30 | public String getId() { 31 | return "sea.redis.stats.collector"; 32 | } 33 | @Override 34 | public Map getProperties() { 35 | log.debug("collect redis info"); 36 | Map map = new HashMap<>(); 37 | List data = new ArrayList<>(); 38 | String beanName = ""; 39 | try { 40 | beanName = "redisCacheService"; 41 | JedisPoolConfig poolConfig = SpringContextHolder.getBean("poolConfig"); 42 | JedisConnectionFactory connectionFactory = SpringContextHolder.getBeanSafe("jedisConnectionFactory"); 43 | Object poolObj = ReflectUtil.read(connectionFactory, "pool"); 44 | if (poolObj != null) { 45 | Pool pool = (Pool) poolObj; 46 | RedisMonitorInfo monitorInfo = new RedisMonitorInfo(); 47 | monitorInfo.setServiceName(beanName); 48 | monitorInfo.setActiveCount(pool.getNumActive()); 49 | monitorInfo.setIdleCount(pool.getNumIdle()); 50 | monitorInfo.setWaiterCount(pool.getNumWaiters()); 51 | monitorInfo.setTotalCount(poolConfig.getMaxTotal()); 52 | convertToMetricList(monitorInfo, data); 53 | } 54 | } catch (Exception e) { 55 | log.error("fail to collect redis info", e); 56 | } 57 | 58 | map.put("data", data); 59 | return map; 60 | } 61 | private void convertToMetricList(RedisMonitorInfo monitorInfo, List data) { 62 | addMetric(data, MonitorConst.METRIC_REDIS_ACTIVE_COUNT, monitorInfo.getActiveCount(), TagConst.SERVICE, monitorInfo.getServiceName()); 63 | addMetric(data, MonitorConst.METRIC_REDIS_IDLE_COUNT, monitorInfo.getIdleCount(), TagConst.SERVICE, monitorInfo.getServiceName()); 64 | addMetric(data, MonitorConst.METRIC_REDIS_WAITER_COUNT, monitorInfo.getWaiterCount(), TagConst.SERVICE, monitorInfo.getServiceName()); 65 | addMetric(data, MonitorConst.METRIC_REDIS_TOTAL_COUNT, monitorInfo.getTotalCount(), TagConst.SERVICE, monitorInfo.getServiceName()); 66 | addMetric(data, MonitorConst.METRIC_REDIS_ACTIVE_PERCENT, NumberUtil.divide(monitorInfo.getActiveCount(), monitorInfo.getTotalCount(), 3, RoundingMode.UP).doubleValue(), TagConst.SERVICE, monitorInfo.getServiceName()); 67 | } 68 | private void addMetric(List data, String key, double value, String tag1Key, String tag2Value) { 69 | MetricDTO metricDTO = new MetricDTO(); 70 | metricDTO.setMetric(key); 71 | metricDTO.setValue(value); 72 | Map tagsMap = new HashMap<>(); 73 | tagsMap.put(tag1Key, tag2Value); 74 | metricDTO.setTagsMap(tagsMap); 75 | data.add(metricDTO); 76 | } 77 | } 78 | ```` -------------------------------------------------------------------------------- /doc/rocketmq.md: -------------------------------------------------------------------------------- 1 | # RocketMQ-Broker监控 2 | 3 | ## 指标 4 | | 指标名称 | 描述 | 5 | | ---- | ---- | 6 | | mq.consumer.tps | 消费者TPS | 7 | | mq.consumer.count | 消费者个数 | 8 | | mq.consumer.min.count.delta | 消费者最小值变化量,可以以此为监控项 | 9 | | mq.consumer.diff.total | 消费堆积数 | 10 | | mq.consumer.diff.total.delta | 消费堆积变化量,可以以此为监控项 | 11 | 12 | 13 | ## rocketmq-console定制 14 | 15 | ### 前端 16 | ![](img/rocketmq-monitor.png) 17 | 18 | 取消注释 19 | 20 | ### 后端 21 | 22 | `src/main/java/org/apache/rocketmq/console/task/MonitorTask.java` 23 | 24 | ```` 25 | @Component 26 | public class MonitorTask { 27 | private Logger logger = LoggerFactory.getLogger(MonitorTask.class); 28 | 29 | @Resource 30 | private MonitorService monitorService; 31 | 32 | @Resource 33 | private ConsumerService consumerService; 34 | 35 | @Scheduled(cron = "0/20 * * * * ?") 36 | public void scanProblemConsumeGroup() { 37 | 38 | logger.info("scan consumer info."); 39 | 40 | List data = new ArrayList<>(); 41 | for (Map.Entry configEntry : monitorService.queryConsumerMonitorConfig().entrySet()) { 42 | GroupConsumeInfo consumeInfo = consumerService.queryGroup(configEntry.getKey()); 43 | 44 | Map tagMap = new HashMap<>(); 45 | tagMap.put(TagConst.SERVICE, configEntry.getKey()); 46 | 47 | Map map = new HashMap<>(); 48 | 49 | map.put("mq.consumer.tps", consumeInfo.getConsumeTps()); 50 | map.put("mq.consumer.count", consumeInfo.getCount()); 51 | map.put("mq.consumer.min.count.delta", consumeInfo.getCount() - configEntry.getValue().getMinCount()); 52 | map.put("mq.consumer.diff.total", consumeInfo.getDiffTotal()); 53 | map.put("mq.consumer.diff.total.delta", consumeInfo.getDiffTotal() - configEntry.getValue().getMaxDiffTotal()); 54 | 55 | 56 | MonitorInfoDTO monitorInfoDTO = new MonitorInfoDTO(); 57 | monitorInfoDTO.setMetricMap(map); 58 | monitorInfoDTO.setTagMap(tagMap); 59 | data.add(monitorInfoDTO); 60 | } 61 | send(data); 62 | } 63 | 64 | private void send(List data) { 65 | if (ListUtil.isEmpty(data)) { 66 | return; 67 | } 68 | 69 | data.stream() 70 | .parallel() 71 | .forEach(infoDTO -> { 72 | 73 | infoDTO.getMetricMap().entrySet().stream().forEach(item -> { 74 | MetricDTO metricDTO = new MetricDTO(); 75 | metricDTO.setMetric(item.getKey()); 76 | metricDTO.setValue(Double.valueOf(item.getValue().toString())); 77 | 78 | Map tagsMap = new HashMap<>(); 79 | tagsMap.put(TagConst.SERVICE, infoDTO.getTagMap().get(TagConst.SERVICE)); 80 | metricDTO.setTagsMap(tagsMap); 81 | metricDTO.setStep(20); 82 | SeaMonitor.logMetric(metricDTO); 83 | }); 84 | }); 85 | } 86 | 87 | @Data 88 | private class MonitorInfoDTO { 89 | private Map metricMap; 90 | private Map tagMap; 91 | } 92 | 93 | 94 | } 95 | ```` 96 | 97 | ## 构建&启动 98 | 99 | ```` 100 | nohup java -jar rocketmq-console-ng-1.0.1.jar \ 101 | --rocketmq.config.namesrvAddr=172.17.8.101:9876 \ 102 | --sea.monitor.enabled=true \ 103 | --sea.monitor.uri=http://127.0.0.1:2058/api/collector/push & 104 | ```` -------------------------------------------------------------------------------- /doc/system.md: -------------------------------------------------------------------------------- 1 | # System 2 | 3 | ## 指标 4 | |指标明|描述| 5 | |----|----| 6 | |sea.sys.reboot|重启指标| 7 | |sea.sys.alive|进程存在指标,1min一次| 8 | |sea.sys.error.count|应用整体错误量,1min一次,这个指标很重要,可以用来衡量新功能上线后是否有异常| 9 | 10 | 11 | ## 配置 12 | 无需配置,自动上报 -------------------------------------------------------------------------------- /doc/threadPool.md: -------------------------------------------------------------------------------- 1 | # ThreadPool监控 2 | 3 | ## 指标 4 | 5 | |指标|描述| 6 | |----|----| 7 | |xxx.max|线程池最大数| 8 | |xxx.core|线程池核心数| 9 | |xxx.largest|线程池最大数(到目前为止)| 10 | |xxx.active|线程吃活跃数| 11 | |xxx.task|线程池执行任务数| 12 | |xxx.active.percent|线程池使用率| 13 | 14 | 15 | ## 集成 16 | 17 | 手动集成 18 | 19 | 20 | ## 示例 21 | 22 | ```` 23 | META-INF/service/com.github.seaframework.monitor.heartbeat.StatusExtension 24 | ```` 25 | 26 | ```` 27 | com.xxx.user.biz.sys.metric.UserThreadPoolStatusExtension 28 | /** 29 | * module name 30 | * 31 | * @author spy 32 | * @version 1.0 2020/4/9 33 | * @since 1.0 34 | */ 35 | @Slf4j 36 | public class UserThreadPoolStatusExtension implements StatusExtension { 37 | private static final String PREFIX = "user.thread.pool"; 38 | @Override 39 | public String getDescription() { 40 | return PREFIX; 41 | } 42 | @Override 43 | public String getId() { 44 | return PREFIX; 45 | } 46 | @Override 47 | public Map getProperties() { 48 | Map map = new HashMap<>(); 49 | Map poolExecutorMap = ThreadPoolExecutorUtil.getInstance(); 50 | if (MapUtil.isEmpty(poolExecutorMap)) { 51 | return map; 52 | } 53 | poolExecutorMap.forEach((key, value) -> { 54 | ThreadPoolStatus status = ThreadPoolUtil.getStatus(value); 55 | map.put(PREFIX + ".max", status.getMax()); 56 | map.put(PREFIX + ".core", status.getCore()); 57 | map.put(PREFIX + ".largest", status.getLargest()); 58 | map.put(PREFIX + ".active", status.getActive()); 59 | map.put(PREFIX + ".task", status.getTask()); 60 | map.put(PREFIX + ".active.percent", status.getActivePercent()); 61 | }); 62 | return map; 63 | } 64 | } 65 | ```` -------------------------------------------------------------------------------- /doc/tomcat.md: -------------------------------------------------------------------------------- 1 | ## Tomcat监控 2 | 3 | ## 指标 4 | |指标|描述| 5 | |----|----| 6 | |tomcat.http.request.count| 请求数 | 7 | |tomcat.http.error.count| error数量 | 8 | |tomcat.http.processing.time| 处理时间 | 9 | |tomcat.http.max.time| http最大处理时间 | 10 | |tomcat.http.bytes.received| http接收数据量大小 | 11 | |tomcat.http.bytes.sent| http发送数据量大小 | 12 | |tomcat.thread.pool.busy| tomcat线程池活跃数 | 13 | |tomcat.thread.pool.max| tomcat线程池最大值 | 14 | |tomcat.thread.pool.busy.percent| tomcat线程池使用率,超过0.9可以告警 | 15 | 16 | ## 配置 17 | 无需配置,自动探测 -------------------------------------------------------------------------------- /doc/trace.md: -------------------------------------------------------------------------------- 1 | # 直达异常链路 2 | 3 | ## 效果 4 | ![](img/alarm-1.png) 5 | 6 | ## 原理 7 | 8 | 在每次请求过程中,系统会产生traceId(可参考集成sofa-tracer),将traceId写入 N9E API的`extra`字段中, dingtalk-sender解析traceId即可。 9 | 10 | ## 示例 11 | 12 | - 这里已sofa-tracer集成为例 13 | - `src/main/resources/META-INF/services/com.github.seaframework.monitor.trace.TraceExtension`中配置自定义的traceId实现(sofa-trace已内置) 14 | 15 | ```` 16 | @LoadLevel(name = "default") // 注意这里name,最终配置再sea.monitor.trace中 17 | public class DefaultTraceExtension implements TraceExtension { 18 | 19 | @Override 20 | public String getTraceId() { 21 | try { 22 | SofaTracerSpanContext spanContext = SofaTraceContextHolder.getSofaTraceContext() 23 | .getCurrentSpan() 24 | .getSofaTracerSpanContext(); 25 | return spanContext.getTraceId(); 26 | } catch (Exception e) { 27 | log.error("fail to get span_id"); 28 | } 29 | 30 | return ""; 31 | } 32 | } 33 | ```` 34 | - `sea.monitor.properties`文件配置`sea.monitor.trace=default` 35 | - API使用 36 | 37 | ```` 38 | MetricDTO metricDTO = new MetricDTO(); 39 | .... 40 | metricDTO.setTraceIdFlag(true); //重点 41 | .... 42 | ```` -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | sea-root 9 | com.github.seaframework 10 | 2.0.0 11 | 12 | 13 | 14 | com.github.seaframework 15 | sea-monitor-all 16 | 1.3.1 17 | pom 18 | 19 | 20 | sea-monitor 21 | sea-monitor-boot-starter 22 | sea-monitor-boot-starter-demo 23 | sea-monitor-web-demo 24 | 25 | 26 | 27 | 1.0.0 28 | 3.0.12 29 | 30 | 31 | 32 | 33 | 34 | 35 | com.github.seaframework 36 | sea-core-basic 37 | ${sea.core.version} 38 | 39 | 40 | 41 | com.github.seaframework 42 | sea-monitor 43 | ${project.version} 44 | 45 | 46 | 47 | com.github.seaframework 48 | sea-monitor-boot-starter 49 | ${project.version} 50 | 51 | 52 | 53 | com.alipay.sofa 54 | tracer-core 55 | ${sofa.tracer.version} 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | com.github.seaframework 7 | sea-monitor-all 8 | 1.3.1 9 | 10 | 4.0.0 11 | 12 | sea-monitor-boot-starter-demo 13 | 14 | 15 | true 16 | 17 | 18 | 19 | 20 | org.projectlombok 21 | lombok 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | com.h2database 33 | h2 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | 43 | com.github.seaframework 44 | sea-monitor-boot-starter 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | org.apache.maven.plugins 56 | maven-deploy-plugin 57 | 58 | true 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter-demo/src/main/java/com/github/seaframework/monitor/boot/demo/SeaMonitorApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.boot.demo; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * module name 9 | * 10 | * @author spy 11 | * @version 1.0 2020/4/16 12 | * @since 1.0 13 | */ 14 | @Slf4j 15 | @SpringBootApplication 16 | public class SeaMonitorApplication { 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(SeaMonitorApplication.class, args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter-demo/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8800 3 | 4 | sea: 5 | monitor: 6 | enabled: true 7 | endpoint: github-sea-boot-starter-demo 8 | uri: http://127.0.0.1:2058/api/collector/push 9 | filter: 10 | enabled: true 11 | region: usa -------------------------------------------------------------------------------- /sea-monitor-boot-starter-demo/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8800 3 | 4 | spring: 5 | profiles: 6 | active: local 7 | application: 8 | name: github-sea-monitor-boot-demo 9 | logging: 10 | file: ${spring.application.name} 11 | path: ${user.home}/logs/${spring.application.name} -------------------------------------------------------------------------------- /sea-monitor-boot-starter-demo/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 11 | 13 | 14 | 15 | 16 | 17 | %d{HH:mm:ss.SSS} %5level [%t] [%class{36}:%line] [%X{REQUEST_ID}] - %m %n 18 | 19 | 20 | 21 | 22 | ${LOG_PATH}/${LOG_FILE}.log 23 | 24 | %d{yyyy-MM-dd HH:mm:ss.SSS} %5level [%t] [%class{36}:%line] [%X{REQUEST_ID}] - %m %n 25 | 26 | 27 | ${LOG_PATH}/${LOG_FILE}.log.%d{yyyyMMdd} 28 | 180 29 | 30 | 31 | 32 | 33 | 34 | 35 | ${LOG_PATH}/${LOG_FILE}.error.log 36 | 37 | ${LOG_PATH}/${LOG_FILE}.error.log.%d{yyyyMMdd} 38 | 180 39 | 40 | 41 | %d{yyyy-MM-dd HH:mm:ss.SSS} %5level [%t] [%class{36}:%line] [%X{REQUEST_ID}] - %m %n 42 | 43 | 44 | ERROR 45 | ACCEPT 46 | DENY 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | com.github.seaframework 7 | sea-monitor-all 8 | 1.3.1 9 | 10 | 4.0.0 11 | 12 | sea-monitor-boot-starter 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-autoconfigure 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-configuration-processor 23 | true 24 | 25 | 26 | 27 | com.github.seaframework 28 | sea-monitor 29 | 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | true 35 | 36 | 37 | 38 | com.alibaba 39 | fastjson 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-web 45 | 46 | 47 | org.apache.logging.log4j 48 | * 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter/src/main/java/com/github/seaframework/monitor/boot/autoconfigure/SeaMonitorAutoConfigure.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.boot.autoconfigure; 2 | 3 | import com.github.seaframework.core.util.ArrayUtil; 4 | import com.github.seaframework.core.util.ListUtil; 5 | import com.github.seaframework.core.util.StringUtil; 6 | import com.github.seaframework.monitor.aop.SeaMonitorAspect; 7 | import com.github.seaframework.monitor.boot.autoconfigure.listener.SpringApplicationStartListener; 8 | import com.github.seaframework.monitor.filter.SeaMonitorFilter; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 12 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 13 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.context.annotation.Configuration; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * module name 21 | * 22 | * @author spy 23 | * @version 1.0 2020/4/16 24 | * @since 1.0 25 | */ 26 | @Slf4j 27 | @Configuration 28 | @EnableConfigurationProperties(com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties.class) 29 | public class SeaMonitorAutoConfigure { 30 | 31 | @Bean 32 | public SpringApplicationStartListener seaMonitorSpringApplicationStartListener() { 33 | return new SpringApplicationStartListener(); 34 | } 35 | 36 | @Value("${sea.monitor.filter.exclude:}") 37 | private String exclude; 38 | 39 | @Value("${sea.monitor.filter.urlPatterns:/*}") 40 | private List urlPatterns; 41 | 42 | @Value("${sea.monitor.filter.order:1}") 43 | private Integer filterOrder; 44 | 45 | @Bean 46 | @ConditionalOnProperty(name = "sea.monitor.filter.enabled", havingValue = "true", matchIfMissing = true) 47 | public FilterRegistrationBean seaMonitorFilter() { 48 | log.info("init sea monitor filter bean"); 49 | SeaMonitorFilter seaMonitorFilter = new SeaMonitorFilter(); 50 | 51 | FilterRegistrationBean registration = new FilterRegistrationBean(); 52 | registration.setFilter(seaMonitorFilter); 53 | 54 | if (StringUtil.isNotEmpty(exclude)) { 55 | registration.addInitParameter("exclude", exclude); 56 | } 57 | if (ListUtil.isEmpty(urlPatterns)) { 58 | registration.addUrlPatterns("/*"); 59 | } else { 60 | registration.addUrlPatterns(ArrayUtil.toArray(urlPatterns)); 61 | } 62 | registration.setName("sea-monitor-filter"); 63 | registration.setOrder(filterOrder); //值越小,Filter越靠前。 64 | return registration; 65 | } 66 | 67 | @Bean 68 | @ConditionalOnProperty(name = "sea.monitor.enabled", havingValue = "true", matchIfMissing = true) 69 | public SeaMonitorAspect seaMonitorAspect() { 70 | return new SeaMonitorAspect(); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter/src/main/java/com/github/seaframework/monitor/boot/autoconfigure/SeaMonitorProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.boot.autoconfigure; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * module name 11 | * 12 | * @author spy 13 | * @version 1.0 2020/4/16 14 | * @since 1.0 15 | */ 16 | @Data 17 | @ConfigurationProperties("sea") 18 | public class SeaMonitorProperties { 19 | 20 | private String region; 21 | 22 | @NestedConfigurationProperty 23 | private Monitor monitor; 24 | 25 | @NestedConfigurationProperty 26 | private Sample sample; 27 | 28 | @NestedConfigurationProperty 29 | private Send send; 30 | 31 | @NestedConfigurationProperty 32 | private Filter filter; 33 | 34 | @Data 35 | public static class Monitor { 36 | private Boolean enabled; 37 | private String endpoint; 38 | private Integer mode; 39 | private String trace; 40 | private String uri; 41 | } 42 | 43 | @Data 44 | public static class Sample { 45 | private Integer percent; 46 | } 47 | 48 | @Data 49 | public static class Send { 50 | @NestedConfigurationProperty 51 | private Period period; 52 | } 53 | 54 | @Data 55 | public static class Period { 56 | private Integer time; 57 | } 58 | 59 | @Data 60 | public static class Filter { 61 | // 是否启用,默认启用 62 | private Boolean enabled; 63 | // 拦截的url 64 | private List urlPatterns; 65 | // 排除的url 66 | private String exclude; 67 | // filter order 68 | private Integer order; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter/src/main/java/com/github/seaframework/monitor/boot/autoconfigure/listener/SpringApplicationStartListener.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.boot.autoconfigure.listener; 2 | 3 | import com.github.seaframework.core.config.Configuration; 4 | import com.github.seaframework.core.config.ConfigurationFactory; 5 | import com.github.seaframework.core.util.StringUtil; 6 | import com.github.seaframework.monitor.SeaMonitor; 7 | import com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties; 8 | import com.github.seaframework.monitor.common.MonitorConst; 9 | import com.github.seaframework.monitor.enums.MonitorModeEnum; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.boot.context.event.ApplicationReadyEvent; 14 | import org.springframework.context.ApplicationListener; 15 | import org.springframework.context.support.AbstractApplicationContext; 16 | 17 | /** 18 | * module name 19 | * 20 | * @author spy 21 | * @version 1.0 2020/4/16 22 | * @since 1.0 23 | */ 24 | @Slf4j 25 | public class SpringApplicationStartListener implements ApplicationListener { 26 | 27 | @Autowired 28 | private AbstractApplicationContext ctx; 29 | 30 | @Override 31 | public void onApplicationEvent(ApplicationReadyEvent event) { 32 | log.info("init sea-monitor-boot-starter in application event"); 33 | initSeaMonitor(); 34 | } 35 | 36 | @Autowired 37 | private SeaMonitorProperties properties; 38 | 39 | @Value("${spring.application.name:unkown-app}") 40 | private String appName; 41 | 42 | private void initSeaMonitor() { 43 | if (properties == null) { 44 | log.info("sea monitor properties is null"); 45 | SeaMonitor.disable(); 46 | return; 47 | } 48 | 49 | if (properties.getMonitor() == null 50 | || properties.getMonitor().getEnabled() == null 51 | || !properties.getMonitor().getEnabled() 52 | ) { 53 | log.info("sea monitor is null or enable is null"); 54 | SeaMonitor.disable(); 55 | return; 56 | } 57 | log.info("init sea monitor config by boot starter"); 58 | SeaMonitor.enable(); 59 | String region = StringUtil.defaultIfEmpty(properties.getRegion(), "default"); 60 | 61 | Configuration cfg = ConfigurationFactory.getInstance(); 62 | 63 | Integer percent; 64 | if (properties.getSample() == null) { 65 | percent = MonitorConst.DEFAULT_SAMPLE_PERCENT; 66 | } else { 67 | percent = properties.getSample().getPercent(); 68 | if (percent != null && percent >= 0 && percent <= 100) { 69 | } else { 70 | percent = MonitorConst.DEFAULT_SAMPLE_PERCENT; 71 | } 72 | } 73 | Integer periodTime; 74 | if (properties.getSend() == null) { 75 | periodTime = MonitorConst.DEFAULT_PUSH_PERIOD_TIME; 76 | } else { 77 | if (properties.getSend().getPeriod() == null) { 78 | periodTime = MonitorConst.DEFAULT_PUSH_PERIOD_TIME; 79 | } else { 80 | periodTime = properties.getSend().getPeriod().getTime(); 81 | if (periodTime == null || periodTime <= 0) { 82 | periodTime = MonitorConst.DEFAULT_PUSH_PERIOD_TIME; 83 | } 84 | } 85 | } 86 | 87 | String endpoint = properties.getMonitor().getEndpoint(); 88 | if (StringUtil.isEmpty(endpoint)) { 89 | endpoint = appName; 90 | } 91 | Integer mode = properties.getMonitor().getMode(); 92 | if (mode == null) { 93 | mode = MonitorModeEnum.REPORT.ordinal(); 94 | } 95 | String traceExtensionName = properties.getMonitor().getTrace(); 96 | if (StringUtil.isEmpty(traceExtensionName)) { 97 | traceExtensionName = StringUtil.EMPTY; 98 | } 99 | 100 | cfg.putString(MonitorConst.CONFIG_KEY_APP_NAME, appName); 101 | cfg.putString(MonitorConst.CONFIG_KEY_ENABLED, "true"); 102 | cfg.putString(MonitorConst.CONFIG_KEY_REGION, region); 103 | cfg.putString(MonitorConst.CONFIG_KEY_MODE, "" + mode); 104 | cfg.putString(MonitorConst.CONFIG_KEY_TRACE, traceExtensionName); 105 | cfg.putString(MonitorConst.CONFIG_KEY_SAMPLE_PERCENT, "" + percent); 106 | cfg.putString(MonitorConst.CONFIG_KEY_ENDPOINT, endpoint); 107 | cfg.putString(MonitorConst.CONFIG_KEY_URI, properties.getMonitor().getUri()); 108 | cfg.putString(MonitorConst.CONFIG_KEY_CONSUMER_COUNT, "" + MonitorConst.DEFAULT_CONSUMER_COUNT); 109 | cfg.putString(MonitorConst.CONFIG_KEY_SEND_ELEMENT_MAX_COUNT, "" + MonitorConst.DEFAULT_SEND_ELEMENT_MAX_COUNT); 110 | cfg.putString(MonitorConst.CONFIG_KEY_SEND_PERIOD_TIME, "" + periodTime); 111 | 112 | new Thread(() -> SeaMonitor.initialize()).start(); 113 | 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /sea-monitor-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "groups": [ 3 | { 4 | "name": "sea", 5 | "type": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 6 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties" 7 | } 8 | ], 9 | "properties": [ 10 | { 11 | "name": "sea.region", 12 | "type": "java.lang.String", 13 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 14 | "defaultValue": "default", 15 | "description": "区域名称,推荐使用拼音或英文" 16 | }, 17 | { 18 | "name": "sea.monitor.enabled", 19 | "type": "java.lang.Boolean", 20 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 21 | "defaultValue": false, 22 | "description": "是否启用SeaMonitor,默认false." 23 | }, 24 | { 25 | "name": "sea.monitor.endpoint", 26 | "type": "java.lang.String", 27 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 28 | "defaultValue": "", 29 | "description": "应用名称" 30 | }, 31 | { 32 | "name": "sea.monitor.mode", 33 | "type": "java.lang.String", 34 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 35 | "defaultValue": "0", 36 | "description": "log mode. 0 report to remote server (by default); 1 log to local log file" 37 | }, 38 | { 39 | "name": "sea.monitor.trace", 40 | "type": "java.lang.String", 41 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 42 | "defaultValue": "", 43 | "description": "traceId生成方式,默认没有,default:sofa-trace实现" 44 | }, 45 | { 46 | "name": "sea.monitor.uri", 47 | "type": "java.lang.String", 48 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 49 | "defaultValue": "http://127.0.0.1:2058/api/collector/push", 50 | "description": "sea monitor collector server push api url." 51 | }, 52 | { 53 | "name": "sea.monitor.sample.percent", 54 | "type": "java.lang.Integer", 55 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 56 | "defaultValue": 100, 57 | "description": "监控消息采样率,默认100." 58 | }, 59 | { 60 | "name": "sea.monitor.send.period.time", 61 | "type": "java.lang.Integer", 62 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 63 | "defaultValue": 20, 64 | "description": "20." 65 | }, 66 | { 67 | "name": "sea.monitor.filter.enabled", 68 | "type": "java.lang.Boolean", 69 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 70 | "defaultValue": true, 71 | "description": "enable sea monitor web filter." 72 | }, 73 | { 74 | "name": "sea.monitor.filter.urlPatterns", 75 | "type": "java.lang.String", 76 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 77 | "defaultValue": "/*", 78 | "description": "sea monitor filter filter url." 79 | }, 80 | { 81 | "name": "sea.monitor.filter.exclude", 82 | "type": "java.lang.String", 83 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 84 | "defaultValue": "", 85 | "description": "sea monitor filter exclude url." 86 | }, 87 | { 88 | "name": "sea.monitor.filter.order", 89 | "type": "java.lang.Integer", 90 | "sourceType": "com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorProperties", 91 | "defaultValue": 1, 92 | "description": "sea monitor filter order, default 1." 93 | } 94 | ] 95 | } -------------------------------------------------------------------------------- /sea-monitor-boot-starter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.github.seaframework.monitor.boot.autoconfigure.SeaMonitorAutoConfigure -------------------------------------------------------------------------------- /sea-monitor-boot-starter/src/main/resources/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/sea-monitor-boot-starter/src/main/resources/README.md -------------------------------------------------------------------------------- /sea-monitor-web-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | 8 | com.github.seaframework 9 | sea-monitor-all 10 | 1.3.1 11 | 12 | 13 | com.github.seaframework 14 | sea-monitor-web-demo 15 | war 16 | 17 | sea-monitor-web-demo 18 | 19 | 20 | 4.12 21 | 1.2.56 22 | 23 | 24 | 25 | 4.3.22.RELEASE 26 | 1.3.6 27 | true 28 | 29 | 30 | 31 | 32 | com.github.seaframework 33 | sea-monitor 34 | 35 | 36 | 37 | com.github.seaframework 38 | sea-core-basic 39 | 40 | 41 | 42 | ch.qos.logback 43 | logback-classic 44 | 45 | 46 | 47 | org.projectlombok 48 | lombok 49 | true 50 | 51 | 52 | 53 | 54 | org.springframework 55 | spring-core 56 | ${spring.version} 57 | 58 | 59 | org.springframework 60 | spring-beans 61 | ${spring.version} 62 | 63 | 64 | org.springframework 65 | spring-context 66 | ${spring.version} 67 | 68 | 69 | org.springframework 70 | spring-aop 71 | ${spring.version} 72 | 73 | 74 | org.springframework 75 | spring-aspects 76 | ${spring.version} 77 | 78 | 79 | org.springframework 80 | spring-expression 81 | ${spring.version} 82 | 83 | 84 | org.springframework 85 | spring-instrument 86 | ${spring.version} 87 | 88 | 89 | org.springframework 90 | spring-oxm 91 | ${spring.version} 92 | 93 | 94 | org.springframework 95 | spring-web 96 | ${spring.version} 97 | 98 | 99 | org.springframework 100 | spring-webmvc 101 | ${spring.version} 102 | 103 | 104 | org.springframework 105 | spring-tx 106 | ${spring.version} 107 | 108 | 109 | org.springframework 110 | spring-test 111 | ${spring.version} 112 | 113 | 114 | javax.servlet 115 | javax.servlet-api 116 | 117 | 118 | 119 | com.alibaba 120 | dubbo 121 | 122 | 123 | com.101tec 124 | zkclient 125 | 126 | 127 | 128 | com.alipay.sofa 129 | sofa-tracer-springmvc-plugin 130 | ${sofa.tracer.version} 131 | 132 | 133 | 134 | 135 | sea-monitor-web-demo 136 | 137 | 138 | org.apache.maven.plugins 139 | maven-deploy-plugin 140 | 141 | true 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/controller/AbstractController.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.controller; 2 | 3 | /** 4 | * module name 5 | * 6 | * @author spy 7 | * @version 1.0 2020/3/27 8 | * @since 1.0 9 | */ 10 | public abstract class AbstractController { 11 | } 12 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/controller/AbstractTestController.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * module name 7 | * 8 | * @author spy 9 | * @version 1.0 2020/3/27 10 | * @since 1.0 11 | */ 12 | @Slf4j 13 | public class AbstractTestController { 14 | } 15 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/controller/LogController.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * module name 13 | * 14 | * @author spy 15 | * @version 1.0 2020/5/3 16 | * @since 1.0 17 | */ 18 | @Slf4j 19 | @RestController 20 | @RequestMapping("/api/log") 21 | public class LogController { 22 | 23 | @GetMapping("/error") 24 | public Map error() { 25 | log.debug("1111"); 26 | log.info("2222"); 27 | log.error("error"); 28 | Map map = new HashMap(); 29 | return map; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.controller; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import com.github.seaframework.monitor.SeaMonitor; 5 | import com.github.seaframework.monitor.demo.service.UserService; 6 | import com.github.seaframework.monitor.dto.MetricDTO; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import java.util.concurrent.atomic.AtomicLong; 14 | 15 | /** 16 | * module name 17 | * 18 | * @author spy 19 | * @version 1.0 2020/3/27 20 | * @since 1.0 21 | */ 22 | @Slf4j 23 | @RestController 24 | @RequestMapping("/api/test/user") 25 | public class UserController extends AbstractTestController { 26 | 27 | private static AtomicLong count = new AtomicLong(0); 28 | 29 | @Autowired 30 | private UserService userService; 31 | 32 | @GetMapping("/hi") 33 | public String hi() { 34 | 35 | try { 36 | Thread.sleep(RandomUtil.randomInt(1, 30) * 10); 37 | } catch (Exception e) { 38 | 39 | } 40 | log.info("----hi"); 41 | return String.valueOf(count.addAndGet(1)); 42 | } 43 | 44 | @GetMapping("/login") 45 | public String login() { 46 | MetricDTO metricDTO = new MetricDTO(); 47 | metricDTO.setMetric("user.login"); 48 | metricDTO.setValue(1); 49 | metricDTO.setTraceIdFlag(true); 50 | SeaMonitor.logMetric(metricDTO); 51 | 52 | SeaMonitor.logMetric("login", 1); 53 | return "success"; 54 | } 55 | 56 | @GetMapping("/add/exception") 57 | public String addException() { 58 | userService.addException(); 59 | return "success"; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/custom/MyThreadPoolStatusExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.custom; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import com.github.seaframework.monitor.heartbeat.StatusExtension; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * module name 12 | * 13 | * @author spy 14 | * @version 1.0 2020/4/3 15 | * @since 1.0 16 | */ 17 | @Slf4j 18 | public class MyThreadPoolStatusExtension implements StatusExtension { 19 | @Override 20 | public String getDescription() { 21 | return null; 22 | } 23 | 24 | @Override 25 | public String getId() { 26 | return "user"; 27 | } 28 | 29 | @Override 30 | public Map getProperties() { 31 | Map map = new HashMap<>(); 32 | map.put("random", RandomUtil.randomInt(1, 1000)); 33 | return map; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/listener/ApplicationInitListener.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.listener; 2 | 3 | import com.github.seaframework.monitor.SeaMonitor; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import javax.servlet.ServletContextEvent; 7 | import javax.servlet.ServletContextListener; 8 | 9 | /** 10 | * module name 11 | * 12 | * @author spy 13 | * @version 1.0 2020/3/27 14 | * @since 1.0 15 | */ 16 | @Slf4j 17 | public class ApplicationInitListener implements ServletContextListener { 18 | @Override 19 | public void contextInitialized(ServletContextEvent sce) { 20 | SeaMonitor.enable(); 21 | SeaMonitor.initialize(); 22 | } 23 | 24 | @Override 25 | public void contextDestroyed(ServletContextEvent sce) { 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * module name 3 | * 4 | * @author spy 5 | * @version 1.0 2020/3/27 6 | * @since 1.0 7 | */ 8 | package com.github.seaframework.monitor.demo; -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.service; 2 | 3 | /** 4 | * module name 5 | * 6 | * @author spy 7 | * @version 1.0 2020/4/3 8 | * @since 1.0 9 | */ 10 | public interface UserService { 11 | void add(); 12 | 13 | void addException(); 14 | } 15 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.service.impl; 2 | 3 | import com.github.seaframework.monitor.annotation.SeaMonitorTrace; 4 | import com.github.seaframework.monitor.demo.service.UserService; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.stereotype.Service; 7 | 8 | /** 9 | * module name 10 | * 11 | * @author spy 12 | * @version 1.0 2020/4/3 13 | * @since 1.0 14 | */ 15 | @Slf4j 16 | @Service("userService") 17 | public class UserServiceImpl implements UserService { 18 | @Override 19 | public void add() { 20 | log.info("---"); 21 | } 22 | 23 | @Override 24 | @SeaMonitorTrace(metric = "user.add.exception") 25 | public void addException() { 26 | throw new NullPointerException(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/java/com/github/seaframework/monitor/demo/task/UserJob.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.demo.task; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import com.github.seaframework.monitor.SeaMonitor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * module name 10 | * 11 | * @author spy 12 | * @version 1.0 2020/3/28 13 | * @since 1.0 14 | */ 15 | @Slf4j 16 | @Component 17 | public class UserJob { 18 | 19 | // @Scheduled(cron = "0/10 * * * * ?") 20 | public static void report() { 21 | log.info("report"); 22 | SeaMonitor.logMetric("login", RandomUtil.randomInt(10, 100)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/resources/META-INF/services/com.github.seaframework.monitor.heartbeat.StatusExtension: -------------------------------------------------------------------------------- 1 | com.github.seaframework.monitor.demo.custom.MyThreadPoolStatusExtension -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | %d{HH:mm:ss.SSS} %level [%thread] [%class{36}.%M:%line] - %m %n 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/resources/sea.monitor.properties: -------------------------------------------------------------------------------- 1 | # 2 | sea.region=usa 3 | # sea monitor 4 | sea.monitor.enabled=true 5 | # application name 6 | sea.monitor.endpoint=github-sea-monitor-web 7 | # log mode 8 | # 0 report to remote server 9 | # 1 log to local log file 10 | sea.monitor.mode=1 11 | sea.monitor.trace=default 12 | # sea monitor uri 13 | sea.monitor.uri=http://47.99.15.184:31424/api/collector/push 14 | # \u91C7\u6837\u7387 15 | sea.monitor.sample.percent=100 16 | # \u6D88\u8D39\u8005\u4E2A\u6570 17 | sea.monitor.consumer.count=1 18 | # \u53D1\u9001\u7684\u6700\u5927\u5143\u7D20\u4E2A\u6570 19 | sea.monitor.send.element.max.count=200 20 | # \u53D1\u9001\u95F4\u9694 21 | sea.monitor.send.period.time=30 -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/resources/spring/dubbo/spring-dubbo.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/resources/spring/spring-all.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/resources/spring/spring-mvc.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | sea-monitor-demo 7 | 8 | 9 | contextConfigLocation 10 | classpath:spring/spring-all.xml 11 | 12 | 13 | 14 | 15 | com.github.seaframework.monitor.demo.listener.ApplicationInitListener 16 | 17 | 18 | org.springframework.web.context.ContextLoaderListener 19 | 20 | 21 | 22 | sofa-springmvc-tracer 23 | com.alipay.sofa.tracer.plugins.springmvc.SpringMvcSofaTracerFilter 24 | 25 | 26 | sofa-springmvc-tracer 27 | /* 28 | 29 | 30 | 31 | sea-monitor 32 | com.github.seaframework.monitor.filter.SeaMonitorFilter 33 | 34 | 35 | 36 | sea-monitor 37 | /api/* 38 | 39 | 40 | 41 | spring-mvc 42 | org.springframework.web.servlet.DispatcherServlet 43 | 44 | spring MVC 配置文件 45 | contextConfigLocation 46 | classpath:spring/spring-mvc.xml 47 | 48 | 49 | 50 | spring-mvc 51 | / 52 | 53 | 54 | 55 | /index.jsp 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /sea-monitor-web-demo/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | -------------------------------------------------------------------------------- /sea-monitor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | com.github.seaframework 7 | sea-monitor-all 8 | 1.3.1 9 | 10 | 4.0.0 11 | 12 | sea-monitor 13 | 14 | 15 | 16 | 17 | 18 | 19 | org.projectlombok 20 | lombok 21 | true 22 | 23 | 24 | 25 | org.slf4j 26 | slf4j-api 27 | 28 | 29 | 30 | org.slf4j 31 | jcl-over-slf4j 32 | 33 | 34 | 35 | org.slf4j 36 | jul-to-slf4j 37 | 38 | 39 | 40 | javax.servlet 41 | javax.servlet-api 42 | provided 43 | 44 | 45 | 46 | log4j 47 | log4j 48 | true 49 | provided 50 | 51 | 52 | org.apache.logging.log4j 53 | log4j-api 54 | true 55 | provided 56 | 57 | 58 | org.apache.logging.log4j 59 | log4j-core 60 | true 61 | provided 62 | 63 | 64 | ch.qos.logback 65 | logback-classic 66 | true 67 | provided 68 | 69 | 70 | 71 | junit 72 | junit 73 | 74 | 75 | 76 | org.apache.commons 77 | commons-lang3 78 | 79 | 80 | 81 | com.github.seaframework 82 | sea-core-basic 83 | 84 | 85 | 86 | com.lmax 87 | disruptor 88 | 3.4.2 89 | 90 | 91 | 92 | com.alibaba 93 | dubbo 94 | true 95 | 96 | 97 | 98 | org.apache.dubbo 99 | dubbo 100 | true 101 | 102 | 103 | 104 | com.alibaba 105 | druid 106 | 1.0.14 107 | provided 108 | 109 | 110 | 111 | org.mybatis 112 | mybatis 113 | 3.4.6 114 | provided 115 | 116 | 117 | 118 | 119 | org.aspectj 120 | aspectjtools 121 | 122 | 123 | 124 | com.alipay.sofa 125 | tracer-core 126 | provided 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/annotation/SeaMonitorTrace.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * monitor for method. 7 | * 8 | * @author spy 9 | * @version 1.0 2020/4/30 10 | * @since 1.0 11 | */ 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target(ElementType.METHOD) 14 | @Documented 15 | public @interface SeaMonitorTrace { 16 | 17 | String metric() default ""; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/aop/SeaMonitorAspect.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.aop; 2 | 3 | import com.github.seaframework.core.util.StringUtil; 4 | import com.github.seaframework.monitor.SeaMonitor; 5 | import com.github.seaframework.monitor.annotation.SeaMonitorTrace; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.aspectj.lang.ProceedingJoinPoint; 8 | import org.aspectj.lang.annotation.Around; 9 | import org.aspectj.lang.annotation.Aspect; 10 | import org.springframework.core.annotation.Order; 11 | 12 | import java.util.Objects; 13 | 14 | /** 15 | * module name 16 | * 17 | * @author spy 18 | * @version 1.0 2020/4/30 19 | * @since 1.0 20 | */ 21 | @Slf4j 22 | @Aspect 23 | @Order(100) 24 | public class SeaMonitorAspect { 25 | 26 | @Around(value = "@annotation(annotation)", argNames = "joinPoint,annotation") 27 | public Object doAround(ProceedingJoinPoint joinPoint, SeaMonitorTrace annotation) throws Throwable { 28 | if (log.isDebugEnabled()) { 29 | log.debug("sea monitor aspect begin."); 30 | } 31 | 32 | if (Objects.isNull(annotation) || StringUtil.isEmpty(annotation.metric())) { 33 | return joinPoint.proceed(); 34 | } 35 | 36 | try { 37 | Object proceed = joinPoint.proceed(); 38 | return proceed; 39 | } catch (Throwable throwable) { 40 | log.warn("exception500"); 41 | SeaMonitor.logErrorCount(annotation.metric()); 42 | throw throwable; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/common/MonitorCommon.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.common; 2 | 3 | import com.github.seaframework.core.util.ClassUtil; 4 | import com.github.seaframework.monitor.heartbeat.dubbo.DubboLegacyThreadPoolHeartbeat; 5 | import com.github.seaframework.monitor.heartbeat.dubbo.DubboThreadPoolHeartbeat; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | /** 9 | * module name 10 | * 11 | * @author spy 12 | * @version 1.0 2020/4/18 13 | * @since 1.0 14 | */ 15 | @Slf4j 16 | public class MonitorCommon { 17 | private static volatile Boolean hasDubboCheckFlag = false; 18 | private static volatile Boolean hasDubboFlag = null; 19 | 20 | public static boolean hasDubbo() { 21 | if (hasDubboCheckFlag) { 22 | return hasDubboFlag; 23 | } 24 | hasDubboFlag = DubboThreadPoolHeartbeat.exist() || DubboLegacyThreadPoolHeartbeat.exist(); 25 | hasDubboCheckFlag = true; 26 | return hasDubboFlag; 27 | } 28 | 29 | private static volatile boolean isTomcatCheckFlag = false; 30 | private static volatile boolean isTomcatFlag = false; 31 | private static final String CLAZZ_TOMCAT_CONTAINER = "org.apache.catalina.Container"; 32 | 33 | public static boolean isTomcatContainer() { 34 | if (isTomcatCheckFlag) { 35 | return isTomcatFlag; 36 | } 37 | isTomcatFlag = ClassUtil.load(CLAZZ_TOMCAT_CONTAINER) != null; 38 | isTomcatCheckFlag = true; 39 | return isTomcatFlag; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/common/MonitorConst.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.common; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * module name 7 | * 8 | * @author spy 9 | * @version 1.0 2020/3/24 10 | * @since 1.0 11 | */ 12 | @Slf4j 13 | public class MonitorConst { 14 | 15 | public static final String MONITOR_CONFIG_FILE = "sea.monitor.properties"; 16 | 17 | public static final String CONFIG_KEY_REGION = "sea.region"; 18 | //是否启用监控 19 | public static final String CONFIG_KEY_ENABLED = "sea.monitor.enabled"; 20 | // 当前系统名称,当前环境唯一,后期会演化成机器唯一标识,启动后不再变化 21 | public static final String CONFIG_KEY_ENDPOINT = "sea.monitor.endpoint"; 22 | // 当前系统名称 23 | public static final String CONFIG_KEY_APP_NAME = "sea.monitor.application.name"; 24 | // monitor sdk 25 | // @See monitor mode enum 26 | public static final String CONFIG_KEY_MODE = "sea.monitor.mode"; 27 | 28 | public static final String CONFIG_KEY_TRACE = "sea.monitor.trace"; 29 | 30 | // 请求地址 31 | public static final String CONFIG_KEY_URI = "sea.monitor.uri"; 32 | // 采样频率 33 | public static final String CONFIG_KEY_SAMPLE_PERCENT = "sea.monitor.sample.percent"; 34 | // 消费者个数 35 | public static final String CONFIG_KEY_CONSUMER_COUNT = "sea.monitor.consumer.count"; 36 | // 发送最大元素个数 37 | public static final String CONFIG_KEY_SEND_ELEMENT_MAX_COUNT = "sea.monitor.send.element.max.count"; 38 | // 发送间隔 39 | public static final String CONFIG_KEY_SEND_PERIOD_TIME = "sea.monitor.send.period.time"; 40 | 41 | public static final String HTTP = "http"; 42 | public static final String DUBBO = "dubbo"; 43 | public static final String MQ = "mq"; 44 | 45 | public static final String METRIC_EXCEPTION = "exception"; 46 | 47 | // 监控指标 http异常 48 | public static final String METRIC_HTTP_REQUEST_TIME = "http.request.cost.time"; 49 | // 监控指标 - 请求异常 50 | public static final String METRIC_HTTP_ERROR = "http.request.error"; 51 | //监控指标 - 定时任务异常 52 | public static final String METRIC_TASK_ERROR = "task.error"; 53 | 54 | 55 | public static final String METRIC_SYS_REBOOT = "sea.sys.reboot"; 56 | public static final String METRIC_SYS_ALIVE = "sea.sys.alive"; 57 | public static final String METRIC_SYS_ERROR = "sea.sys.error.count"; 58 | 59 | public static final String METRIC_DUBBO_EXCEPTION = "dubbo.exception"; 60 | public static final String METRIC_DUBBO_COST = "dubbo.cost"; 61 | 62 | public static final String METRIC_MQ_ERROR = "mq.error"; 63 | 64 | // redis 65 | public static final String METRIC_REDIS_ACTIVE_COUNT = "redis.pool.active.count"; 66 | public static final String METRIC_REDIS_IDLE_COUNT = "redis.pool.idle.count"; 67 | public static final String METRIC_REDIS_WAITER_COUNT = "redis.pool.waiter.count"; 68 | public static final String METRIC_REDIS_TOTAL_COUNT = "redis.pool.total.count"; 69 | public static final String METRIC_REDIS_ACTIVE_PERCENT = "redis.pool.active.percent"; 70 | 71 | // db 72 | public static final String METRIC_DB_SQL_ERROR = "db.sql.error"; 73 | public static final String METRIC_DB_SQL_LARGE_RECORD_ERROR = "db.sql.large.record.error"; 74 | public static final String METRIC_DB_SQL_ERROR_COUNT = "db.sql.error.count"; 75 | public static final String METRIC_DB_SQL_COST = "db.sql.cost"; 76 | 77 | 78 | // 79 | 80 | 81 | // 默认收集地址 82 | public static final String DEFAULT_COLLECTOR_URI = "http://127.0.0.1:2058/api/collector/push"; 83 | // 处理能力 84 | public static final int DEFAULT_CONSUMER_COUNT = 1; 85 | // 发送元素最大个数 86 | public static final int DEFAULT_SEND_ELEMENT_MAX_COUNT = 200; 87 | // 默认采样率 88 | public static final int DEFAULT_SAMPLE_PERCENT = 100; 89 | /** 90 | * 定时推送监控信息到agent的间隔时间,单位:秒,默认20 91 | */ 92 | public static final int DEFAULT_PUSH_PERIOD_TIME = 20; 93 | 94 | } 95 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/common/TagConst.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.common; 2 | 3 | /** 4 | * module name 5 | * 6 | * @author spy 7 | * @version 1.0 2020/3/24 8 | * @since 1.0 9 | */ 10 | public interface TagConst { 11 | 12 | 13 | String REGION = "region"; 14 | 15 | String URI = "uri"; 16 | 17 | String INSTANCE = "instance"; 18 | 19 | String APP = "app"; 20 | 21 | String HOSTNAME = "hostname"; 22 | 23 | String SERVICE_NAME = "service_name"; 24 | 25 | String CORP_CODE = "corp_code"; 26 | 27 | String HOSPITAL_ID = "hospital_id"; 28 | 29 | String PROTOCOL = "protocol"; 30 | 31 | String HTTP_STATUS = "http_status"; 32 | 33 | String TRACE_ID = "trace_id"; 34 | 35 | String SERVICE = "service"; 36 | 37 | String METHOD = "method"; 38 | 39 | String DB_TYPE = "db_type"; 40 | 41 | String PORT = "port"; 42 | } 43 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/dto/BaseMonitorDTO.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import com.github.seaframework.core.util.MapUtil; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | import java.util.Map; 9 | 10 | /** 11 | * module name 12 | * 13 | * @author spy 14 | * @version 1.0 2020/3/28 15 | * @since 1.0 16 | */ 17 | @Data 18 | public class BaseMonitorDTO implements Serializable { 19 | private String metric; 20 | private String endpoint; 21 | private int step; 22 | private long timestamp; 23 | private Map tagsMap; 24 | 25 | private String extra; 26 | 27 | @JSONField(serialize = false) 28 | private Map extraMap; 29 | 30 | public String getExtra() { 31 | return MapUtil.toString(extraMap); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/dto/MetricDTO.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.dto; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | 7 | /** 8 | * module name 9 | * 10 | * @author spy 11 | * @version 1.0 2020/3/24 12 | * @since 1.0 13 | */ 14 | @Data 15 | @ToString(callSuper = true) 16 | public class MetricDTO extends BaseMonitorDTO { 17 | 18 | /** 19 | * 指标值 20 | */ 21 | private double value; 22 | 23 | /** 24 | * 是否是错误标志,如果是错误类型,会进行sys.error++ 25 | */ 26 | @JSONField(serialize = false) 27 | private boolean errorFlag; 28 | 29 | /** 30 | * 是否添加traceId 31 | */ 32 | @JSONField(serialize = false) 33 | private boolean traceIdFlag; 34 | } 35 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/dubbo/AbstractDubboExceptionMonitorFilter.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.dubbo; 2 | 3 | import com.github.seaframework.monitor.SeaMonitor; 4 | import com.github.seaframework.monitor.common.MonitorConst; 5 | import com.github.seaframework.monitor.common.TagConst; 6 | import com.github.seaframework.monitor.dto.MetricDTO; 7 | import com.google.common.base.Stopwatch; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * module name 16 | * 17 | * @author spy 18 | * @version 1.0 2020/8/14 19 | * @since 1.0 20 | */ 21 | @Slf4j 22 | public abstract class AbstractDubboExceptionMonitorFilter { 23 | // 10s 24 | private static final int MIN_COST_TIME = 1000 * 10; 25 | 26 | 27 | protected void postCheckCost(Stopwatch stopwatch, String service, String method) { 28 | if (stopwatch == null) { 29 | return; 30 | } 31 | if (!SeaMonitor.isEnabled()) { 32 | return; 33 | } 34 | long cost = stopwatch.elapsed(TimeUnit.MILLISECONDS); 35 | if (cost >= MIN_COST_TIME) { 36 | log.warn("DUBBO502"); 37 | MetricDTO metricDTO = new MetricDTO(); 38 | metricDTO.setMetric(MonitorConst.METRIC_DUBBO_COST); 39 | metricDTO.setValue(cost); 40 | metricDTO.setTraceIdFlag(true); 41 | 42 | Map tagsMap = new HashMap<>(2); 43 | tagsMap.put(TagConst.SERVICE, service); 44 | tagsMap.put(TagConst.METHOD, method); 45 | metricDTO.setTagsMap(tagsMap); 46 | 47 | SeaMonitor.logMetric(metricDTO); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/dubbo/alibaba/DubboExceptionMonitorFilter.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.dubbo.alibaba; 2 | 3 | import com.alibaba.dubbo.rpc.*; 4 | import com.github.seaframework.monitor.SeaMonitor; 5 | import com.github.seaframework.monitor.common.MonitorConst; 6 | import com.github.seaframework.monitor.dto.MetricDTO; 7 | import com.github.seaframework.monitor.dubbo.AbstractDubboExceptionMonitorFilter; 8 | import com.github.seaframework.monitor.enums.CounterEnum; 9 | import com.github.seaframework.monitor.heartbeat.data.DataStats; 10 | import com.google.common.base.Stopwatch; 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * module name 18 | * 19 | * @author spy 20 | * @version 1.0 2020/4/13 21 | * @since 1.0 22 | */ 23 | @Slf4j 24 | public class DubboExceptionMonitorFilter extends AbstractDubboExceptionMonitorFilter implements Filter { 25 | @Override 26 | public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { 27 | Stopwatch stopwatch = Stopwatch.createStarted(); 28 | 29 | Throwable exception = null; 30 | Result result = null; 31 | try { 32 | result = invoker.invoke(invocation); 33 | } catch (RpcException e) { 34 | exception = e; 35 | logRPCException(invoker, invocation, e); 36 | throw e; 37 | } catch (Throwable t) { 38 | exception = t; 39 | throw new RpcException(t); 40 | } finally { 41 | if (result.hasException() || exception != null) { 42 | log.error("dubbo500"); 43 | if (SeaMonitor.isEnabled()) { 44 | MetricDTO metricDTO = new MetricDTO(); 45 | metricDTO.setMetric(MonitorConst.METRIC_DUBBO_EXCEPTION); 46 | metricDTO.setValue(1); 47 | Map tags = new HashMap<>(2); 48 | tags.put("service", invoker.getInterface().getName()); 49 | tags.put("method", invocation.getMethodName()); 50 | metricDTO.setTagsMap(tags); 51 | metricDTO.setTraceIdFlag(true); 52 | 53 | SeaMonitor.logMetric(metricDTO); 54 | 55 | // for dubbo total 56 | DataStats dataStats = DataStats.currentStatsHolder(); 57 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_COUNT); 58 | // for system total 59 | dataStats.logCount(CounterEnum.SYS_ERROR); 60 | } 61 | } 62 | postCheckCost(stopwatch, invoker.getInterface().getName(), invocation.getMethodName()); 63 | } 64 | return result; 65 | } 66 | 67 | private void logRPCException(Invoker invoker, Invocation invocation, RpcException exception) { 68 | if (!SeaMonitor.isEnabled()) { 69 | return; 70 | } 71 | 72 | if (exception == null) { 73 | return; 74 | } 75 | log.warn("dubbo rpc exception"); 76 | 77 | 78 | try { 79 | DataStats dataStats = DataStats.currentStatsHolder(); 80 | 81 | switch (exception.getCode()) { 82 | default: 83 | case RpcException.UNKNOWN_EXCEPTION: 84 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_UNKNOWN.getKey()); 85 | break; 86 | case RpcException.NETWORK_EXCEPTION: 87 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_NETWORK.getKey()); 88 | break; 89 | case RpcException.TIMEOUT_EXCEPTION: 90 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_TIMEOUT.getKey()); 91 | break; 92 | case RpcException.BIZ_EXCEPTION: 93 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_BIZ.getKey()); 94 | break; 95 | case RpcException.FORBIDDEN_EXCEPTION: 96 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_FORBIDDEN.getKey()); 97 | break; 98 | case RpcException.SERIALIZATION_EXCEPTION: 99 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_SERIALIZATION.getKey()); 100 | break; 101 | } 102 | } catch (Exception e) { 103 | log.error("fail to collector", e); 104 | } 105 | 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/dubbo/apache/DubboExceptionMonitorFilter.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.dubbo.apache; 2 | 3 | import com.github.seaframework.monitor.SeaMonitor; 4 | import com.github.seaframework.monitor.common.MonitorConst; 5 | import com.github.seaframework.monitor.dto.MetricDTO; 6 | import com.github.seaframework.monitor.dubbo.AbstractDubboExceptionMonitorFilter; 7 | import com.github.seaframework.monitor.enums.CounterEnum; 8 | import com.github.seaframework.monitor.heartbeat.data.DataStats; 9 | import com.google.common.base.Stopwatch; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.dubbo.rpc.*; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * module name 18 | * 19 | * @author spy 20 | * @version 1.0 2020/4/13 21 | * @since 1.0 22 | */ 23 | @Slf4j 24 | public class DubboExceptionMonitorFilter extends AbstractDubboExceptionMonitorFilter implements Filter { 25 | @Override 26 | public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { 27 | Stopwatch stopwatch = Stopwatch.createStarted(); 28 | 29 | Throwable exception = null; 30 | Result result = null; 31 | try { 32 | result = invoker.invoke(invocation); 33 | } catch (RpcException e) { 34 | exception = e; 35 | logRPCException(invoker, invocation, e); 36 | throw e; 37 | } catch (Throwable t) { 38 | exception = t; 39 | throw new RpcException(t); 40 | } finally { 41 | if (result.hasException() || exception != null) { 42 | log.info("dubbo500"); 43 | if (SeaMonitor.isEnabled()) { 44 | MetricDTO metricDTO = new MetricDTO(); 45 | metricDTO.setMetric(MonitorConst.METRIC_DUBBO_EXCEPTION); 46 | metricDTO.setValue(1); 47 | Map tags = new HashMap<>(2); 48 | tags.put("service", invoker.getInterface().getName()); 49 | tags.put("method", invocation.getMethodName()); 50 | metricDTO.setTagsMap(tags); 51 | metricDTO.setTraceIdFlag(true); 52 | 53 | SeaMonitor.logMetric(metricDTO); 54 | 55 | // for dubbo total 56 | DataStats dataStats = DataStats.currentStatsHolder(); 57 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_COUNT); 58 | // for system total 59 | dataStats.logCount(CounterEnum.SYS_ERROR); 60 | } 61 | } 62 | 63 | postCheckCost(stopwatch, invoker.getInterface().getName(), invocation.getMethodName()); 64 | } 65 | 66 | return result; 67 | } 68 | 69 | 70 | private void logRPCException(Invoker invoker, Invocation invocation, RpcException exception) { 71 | if (!SeaMonitor.isEnabled()) { 72 | return; 73 | } 74 | if (exception == null) { 75 | return; 76 | } 77 | log.warn("dubbo rpc exception", exception); 78 | 79 | try { 80 | DataStats dataStats = DataStats.currentStatsHolder(); 81 | 82 | switch (exception.getCode()) { 83 | default: 84 | case com.alibaba.dubbo.rpc.RpcException.UNKNOWN_EXCEPTION: 85 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_UNKNOWN.getKey()); 86 | break; 87 | case com.alibaba.dubbo.rpc.RpcException.NETWORK_EXCEPTION: 88 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_NETWORK.getKey()); 89 | break; 90 | case com.alibaba.dubbo.rpc.RpcException.TIMEOUT_EXCEPTION: 91 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_TIMEOUT.getKey()); 92 | break; 93 | case com.alibaba.dubbo.rpc.RpcException.BIZ_EXCEPTION: 94 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_BIZ.getKey()); 95 | break; 96 | case com.alibaba.dubbo.rpc.RpcException.FORBIDDEN_EXCEPTION: 97 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_FORBIDDEN.getKey()); 98 | break; 99 | case com.alibaba.dubbo.rpc.RpcException.SERIALIZATION_EXCEPTION: 100 | dataStats.logCount(CounterEnum.DUBBO_EXCEPTION_SERIALIZATION.getKey()); 101 | break; 102 | } 103 | } catch (Exception e) { 104 | log.error("fail to collector", e); 105 | } 106 | 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/dubbo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * module name 3 | * 4 | * @author spy 5 | * @version 1.0 2020/4/13 6 | * @since 1.0 7 | */ 8 | package com.github.seaframework.monitor.dubbo; -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/enums/CounterEnum.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.enums; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * module name 9 | * 10 | * @author spy 11 | * @version 1.0 2020/4/18 12 | * @since 1.0 13 | */ 14 | @Slf4j 15 | public enum CounterEnum { 16 | // sys 17 | SYS_ERROR("sea.sys.error.count"), 18 | 19 | // query per second 20 | SYS_QPS_COUNT("sea.sys.qps.count"), 21 | SYS_QPS_HTTP_COUNT("sea.sys.qps.http.count"), 22 | SYS_QPS_DUBBO_COUNT("sea.sys.qps.dubbo.count"), 23 | 24 | 25 | // query per minute 26 | SYS_QPM_COUNT("sea.sys.qpm.count"), 27 | SYS_QPM_HTTP_COUNT("sea.sys.qpm.http.count"), 28 | SYS_QPM_DUBBO_COUNT("sea.sys.qpm.dubbo.count"), 29 | 30 | //log for log4j or logback 31 | SYS_LOG_COUNT("sea.sys.log.error.count"), 32 | 33 | // HTTP 34 | HTTP500("http.500.count"), 35 | 36 | //DB 37 | DB_SQL_ERROR_COUNT("db.sql.error.count"), 38 | 39 | // DUBBO 40 | DUBBO_EXCEPTION_COUNT("dubbo.exception.count"), 41 | DUBBO_EXCEPTION_UNKNOWN("dubbo.exception.unknown.count"), 42 | DUBBO_EXCEPTION_BIZ("dubbo.exception.biz.count"), 43 | DUBBO_EXCEPTION_FORBIDDEN("dubbo.exception.forbidden.count"), 44 | DUBBO_EXCEPTION_TIMEOUT("dubbo.exception.timeout.count"), 45 | DUBBO_EXCEPTION_NETWORK("dubbo.exception.network.count"), 46 | DUBBO_EXCEPTION_SERIALIZATION("dubbo.exception.serialization.count"); 47 | 48 | @Getter 49 | @Setter 50 | private String key; 51 | 52 | CounterEnum(String key) { 53 | this.key = key; 54 | } 55 | 56 | public static CounterEnum[] dubboMetricList() { 57 | CounterEnum[] counters = new CounterEnum[]{ 58 | DUBBO_EXCEPTION_UNKNOWN, 59 | DUBBO_EXCEPTION_BIZ, 60 | DUBBO_EXCEPTION_FORBIDDEN, 61 | DUBBO_EXCEPTION_TIMEOUT, 62 | DUBBO_EXCEPTION_NETWORK, 63 | DUBBO_EXCEPTION_SERIALIZATION, 64 | }; 65 | return counters; 66 | } 67 | 68 | public static CounterEnum[] baseMetricList() { 69 | CounterEnum[] counters = new CounterEnum[]{ 70 | SYS_ERROR, 71 | HTTP500, 72 | DB_SQL_ERROR_COUNT, 73 | SYS_LOG_COUNT 74 | }; 75 | return counters; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/enums/MonitorModeEnum.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.enums; 2 | 3 | /** 4 | * module name 5 | * 6 | * @author spy 7 | * @version 1.0 2020/3/25 8 | * @since 1.0 9 | */ 10 | public enum MonitorModeEnum { 11 | REPORT, 12 | LOG; 13 | 14 | 15 | public static MonitorModeEnum of(String value) { 16 | MonitorModeEnum[] values = values(); 17 | 18 | for (int i = 0; i < values.length; i++) { 19 | MonitorModeEnum item = values[i]; 20 | if (item.ordinal() == Integer.valueOf(value).intValue()) { 21 | return item; 22 | } 23 | } 24 | return null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/AbstractCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat; 2 | 3 | import com.github.seaframework.core.config.Configuration; 4 | import com.github.seaframework.core.config.ConfigurationFactory; 5 | import com.github.seaframework.monitor.common.MonitorConst; 6 | import com.github.seaframework.monitor.dto.MetricDTO; 7 | 8 | import java.util.LinkedHashMap; 9 | import java.util.Map; 10 | import java.util.Map.Entry; 11 | 12 | public abstract class AbstractCollector implements StatusExtension { 13 | 14 | protected Map convert(Map map) { 15 | Map result = new LinkedHashMap<>(); 16 | 17 | for (Entry entry : map.entrySet()) { 18 | result.put(entry.getKey(), entry.getValue().toString()); 19 | } 20 | return result; 21 | } 22 | 23 | @Override 24 | public String getDescription() { 25 | return getId(); 26 | } 27 | 28 | protected String getAppName() { 29 | Configuration cfg = ConfigurationFactory.getInstance(); 30 | return cfg.getString(MonitorConst.CONFIG_KEY_APP_NAME, "unkonw-app-anme"); 31 | } 32 | 33 | protected MetricDTO buildMetric(String metric, double value, Map tags) { 34 | MetricDTO metricDTO = new MetricDTO(); 35 | metricDTO.setMetric(metric); 36 | metricDTO.setValue(value); 37 | metricDTO.setTagsMap(tags); 38 | return metricDTO; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/HeartbeatManager.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat; 2 | 3 | /** 4 | * module name 5 | * 6 | * @author spy 7 | * @version 1.0 2020/4/3 8 | * @since 1.0 9 | */ 10 | public interface HeartbeatManager { 11 | 12 | void start(); 13 | 14 | void shutdown(); 15 | } 16 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/StatusExtension.java: -------------------------------------------------------------------------------- 1 | 2 | package com.github.seaframework.monitor.heartbeat; 3 | 4 | import java.util.Map; 5 | 6 | /** 7 | * 扩展接口 8 | */ 9 | public interface StatusExtension { 10 | 11 | /** 12 | * 描述 13 | * 14 | * @return 15 | */ 16 | String getDescription(); 17 | 18 | /** 19 | * 唯一标识 20 | * 21 | * @return 22 | */ 23 | String getId(); 24 | 25 | /** 26 | * 返回指标点 27 | * 28 | * @return 29 | */ 30 | Map getProperties(); 31 | } 32 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/StatusExtensionRegister.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CopyOnWriteArrayList; 5 | 6 | public class StatusExtensionRegister { 7 | 8 | private List extensions = new CopyOnWriteArrayList(); 9 | private static final StatusExtensionRegister register = new StatusExtensionRegister(); 10 | 11 | public static StatusExtensionRegister getInstance() { 12 | return register; 13 | } 14 | 15 | private StatusExtensionRegister() { 16 | } 17 | 18 | public List getStatusExtension() { 19 | return extensions; 20 | } 21 | 22 | public void register(StatusExtension extension) { 23 | extensions.add(extension); 24 | } 25 | 26 | public void unregister(StatusExtension extension) { 27 | extensions.remove(extension); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/biz/BizDataStats.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.biz; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.atomic.AtomicLong; 8 | 9 | /** 10 | * biz common data collector. 11 | * 12 | * @author spy 13 | * @version 1.0 2020/4/18 14 | * @since 1.0 15 | */ 16 | @Slf4j 17 | public class BizDataStats { 18 | private static BizDataStats current = null; 19 | private Map cache = new ConcurrentHashMap<>(); 20 | 21 | private BizDataStats() { 22 | } 23 | 24 | public static BizDataStats currentStatsHolder() { 25 | if (null == current) { 26 | synchronized (BizDataStats.class) { 27 | if (null == current) { 28 | current = new BizDataStats(); 29 | } 30 | } 31 | } 32 | return current; 33 | } 34 | 35 | public static synchronized BizDataStats getAndReset() { 36 | BizDataStats tmp = new BizDataStats(); 37 | BizDataStats old = currentStatsHolder(); 38 | current = tmp; 39 | return old; 40 | } 41 | 42 | 43 | public void logCount(String metric) { 44 | try { 45 | cache.putIfAbsent(metric, new AtomicLong()); 46 | cache.get(metric).incrementAndGet(); 47 | } catch (Exception e) { 48 | // ignore 49 | } 50 | } 51 | 52 | public Map getCache() { 53 | return cache; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/biz/BizDataStatsCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.biz; 2 | 3 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * module name 11 | * 12 | * @author spy 13 | * @version 1.0 2020/4/18 14 | * @since 1.0 15 | */ 16 | @Slf4j 17 | public abstract class BizDataStatsCollector extends AbstractCollector { 18 | @Override 19 | public String getId() { 20 | return "sea.biz.data.stats.collector"; 21 | } 22 | 23 | @Override 24 | public Map getProperties() { 25 | 26 | Map map = new HashMap<>(); 27 | 28 | BizDataStats stats = BizDataStats.getAndReset(); 29 | 30 | stats.getCache() 31 | .entrySet() 32 | .stream() 33 | .parallel() 34 | .forEach(item -> { 35 | map.put(item.getKey(), item.getValue().get()); 36 | }); 37 | 38 | // compensate 39 | metricCompensate(map); 40 | 41 | return map; 42 | } 43 | 44 | /** 45 | * 指标补偿 46 | * 47 | * @param map 48 | */ 49 | protected abstract void metricCompensate(Map map); 50 | } 51 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/biz/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 业务系统自动扩展点 3 | * 4 | * @author spy 5 | * @version 1.0 2020/4/20 6 | * @since 1.0 7 | */ 8 | package com.github.seaframework.monitor.heartbeat.biz; -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/data/DataStats.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.data; 2 | 3 | import com.github.seaframework.monitor.enums.CounterEnum; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | /** 11 | * common data collector for system level, this is very important 12 | * 13 | * @author spy 14 | * @version 1.0 2020/4/18 15 | * @since 1.0 16 | */ 17 | @Slf4j 18 | public class DataStats { 19 | private static DataStats current = null; 20 | private Map cache = new ConcurrentHashMap<>(); 21 | 22 | private DataStats() { 23 | } 24 | 25 | public static DataStats currentStatsHolder() { 26 | if (null == current) { 27 | synchronized (DataStats.class) { 28 | if (null == current) { 29 | current = new DataStats(); 30 | } 31 | } 32 | } 33 | return current; 34 | } 35 | 36 | public static synchronized DataStats getAndReset() { 37 | DataStats tmp = new DataStats(); 38 | DataStats old = currentStatsHolder(); 39 | current = tmp; 40 | return old; 41 | } 42 | 43 | 44 | public void logCount(String metric) { 45 | try { 46 | cache.putIfAbsent(metric, new AtomicLong()); 47 | cache.get(metric).incrementAndGet(); 48 | } catch (Exception e) { 49 | // ignore 50 | } 51 | } 52 | 53 | public void logCount(CounterEnum counterEnum) { 54 | if (counterEnum == null) { 55 | return; 56 | } 57 | logCount(counterEnum.getKey()); 58 | } 59 | 60 | 61 | public Map getCache() { 62 | return cache; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/data/DataStatsCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.data; 2 | 3 | import com.github.seaframework.monitor.common.MonitorCommon; 4 | import com.github.seaframework.monitor.enums.CounterEnum; 5 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * module name 13 | * 14 | * @author spy 15 | * @version 1.0 2020/4/18 16 | * @since 1.0 17 | */ 18 | @Slf4j 19 | public class DataStatsCollector extends AbstractCollector { 20 | @Override 21 | public String getId() { 22 | return "sea.data.stats.collector"; 23 | } 24 | 25 | @Override 26 | public Map getProperties() { 27 | 28 | Map map = new HashMap<>(); 29 | 30 | DataStats stats = DataStats.getAndReset(); 31 | 32 | stats.getCache() 33 | .entrySet() 34 | .stream() 35 | .parallel() 36 | .forEach(item -> { 37 | map.put(item.getKey(), item.getValue().get()); 38 | }); 39 | 40 | // check and compensate dubbo 41 | if (MonitorCommon.hasDubbo()) { 42 | compensateMetric(map, CounterEnum.dubboMetricList()); 43 | } 44 | 45 | // compensate 46 | compensateMetric(map, CounterEnum.baseMetricList()); 47 | 48 | return map; 49 | } 50 | 51 | private void compensateMetric(Map map, CounterEnum[] counters) { 52 | for (int i = 0; i < counters.length; i++) { 53 | map.putIfAbsent(counters[i].getKey(), 0); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/datasource/DataSourceCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.datasource; 2 | 3 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import javax.management.MBeanServer; 7 | import javax.management.ObjectName; 8 | import java.lang.management.ManagementFactory; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * module name 14 | * 15 | * @author spy 16 | * @version 1.0 2020/4/13 17 | * @since 1.0 18 | */ 19 | @Slf4j 20 | public abstract class DataSourceCollector extends AbstractCollector { 21 | private Map lastValueMap = new HashMap(); 22 | protected MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); 23 | protected DatabaseParserHelper databaseParser = new DatabaseParserHelper(); 24 | 25 | protected static final char SPLIT = '.'; 26 | private static final Integer ERROR_INT = -1; 27 | private static final Long ERROR_LONG = -1L; 28 | private static final String ERROR_ATTRIBUTE = "unknown"; 29 | 30 | private Integer diffLast(String key, Integer value) { 31 | Object lastValue = lastValueMap.get(key); 32 | 33 | if (lastValue != null) { 34 | lastValueMap.put(key, value); 35 | return value - (Integer) lastValue; 36 | } else { 37 | lastValueMap.put(key, value); 38 | return value; 39 | } 40 | } 41 | 42 | private Long diffLast(String key, Long value) { 43 | Object lastValue = lastValueMap.get(key); 44 | if (lastValue != null) { 45 | lastValueMap.put(key, value); 46 | return value - (Long) lastValue; 47 | } else { 48 | lastValueMap.put(key, value); 49 | return value; 50 | } 51 | } 52 | 53 | protected String getConnection(Map datasources, String key) { 54 | Integer index = datasources.get(key); 55 | 56 | if (index == null) { 57 | datasources.put(key, 0); 58 | 59 | return key; 60 | } else { 61 | index++; 62 | 63 | datasources.put(key, index); 64 | // return key + '[' + index + ']'; 65 | return key + index; 66 | } 67 | } 68 | 69 | @Override 70 | public String getDescription() { 71 | return "datasource.c3p0"; 72 | } 73 | 74 | @Override 75 | public String getId() { 76 | return "datasource.c3p0"; 77 | } 78 | 79 | protected Integer getIntegerAttribute(ObjectName objectName, String attribute, Boolean isDiff) { 80 | try { 81 | Integer value = (Integer) mbeanServer.getAttribute(objectName, attribute); 82 | if (isDiff) { 83 | return diffLast(objectName.getCanonicalName() + attribute, value); 84 | } else { 85 | return value; 86 | } 87 | } catch (Exception e) { 88 | return ERROR_INT; 89 | } 90 | } 91 | 92 | protected Long getLongAttribute(ObjectName objectName, String attribute, Boolean isDiff) { 93 | try { 94 | Long value = (Long) mbeanServer.getAttribute(objectName, attribute); 95 | if (isDiff) { 96 | return diffLast(objectName.getCanonicalName() + attribute, value); 97 | } else { 98 | return value; 99 | } 100 | } catch (Exception e) { 101 | return ERROR_LONG; 102 | } 103 | } 104 | 105 | protected String getStringAttribute(ObjectName objectName, String attribute) { 106 | try { 107 | return (String) mbeanServer.getAttribute(objectName, attribute); 108 | } catch (Exception e) { 109 | return ERROR_ATTRIBUTE; 110 | } 111 | } 112 | 113 | protected Boolean isRandomName(String name) { 114 | return name != null && name.length() > 30; 115 | } 116 | 117 | protected String getStringByKey(ObjectName objectName, String key) { 118 | try { 119 | return objectName.getKeyProperty(key); 120 | } catch (Exception e) { 121 | return ERROR_ATTRIBUTE; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/datasource/DatabaseParserHelper.java: -------------------------------------------------------------------------------- 1 | 2 | package com.github.seaframework.monitor.heartbeat.datasource; 3 | 4 | import com.github.seaframework.core.util.StringUtil; 5 | import lombok.Data; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.util.LinkedHashMap; 9 | import java.util.Map; 10 | 11 | @Slf4j 12 | public class DatabaseParserHelper { 13 | private Map connections = new LinkedHashMap(); 14 | 15 | private String find(String con, String key) { 16 | int index = con.indexOf(key); 17 | int start = 0; 18 | int end = 0; 19 | if (index > -1) { 20 | for (int i = index + key.length(); i < con.length(); i++) { 21 | if (con.charAt(i) == '=') { 22 | start = i + 1; 23 | } 24 | if (con.charAt(i) == ')') { 25 | end = i; 26 | break; 27 | } 28 | } 29 | } 30 | return con.substring(start, end); 31 | } 32 | 33 | public Database parseDatabase(String connection) { 34 | Database database = connections.get(String.valueOf(connection)); 35 | 36 | if (database == null && StringUtil.isNotEmpty(connection)) { 37 | try { 38 | if (connection.contains("jdbc:mysql://")) { 39 | String con = connection.split("jdbc:mysql://")[1]; 40 | con = con.split("\\?")[0]; 41 | int index = con.indexOf(":"); 42 | String ip = ""; 43 | 44 | if (index < 0) { 45 | ip = con.split("/")[0]; 46 | } else { 47 | ip = con.substring(0, index); 48 | } 49 | 50 | String name = con.substring(con.indexOf("/") + 1); 51 | database = new Database(name, ip); 52 | 53 | connections.put(connection, database); 54 | } else if (connection.contains("jdbc:oracle")) { 55 | if (connection.contains("DESCRIPTION")) { 56 | String name = find(connection, "SERVICE_NAME"); 57 | String ip = find(connection, "HOST"); 58 | 59 | database = new Database(name, ip); 60 | connections.put(connection, database); 61 | } else if (connection.contains("@//")) { 62 | String[] tabs = connection.split("/"); 63 | String name = tabs[tabs.length - 1]; 64 | String ip = tabs[tabs.length - 2]; 65 | int index = ip.indexOf(':'); 66 | 67 | if (index > -1) { 68 | ip = ip.substring(0, index); 69 | } 70 | database = new Database(name, ip); 71 | connections.put(connection, database); 72 | } else { 73 | String[] tabs = connection.split(":"); 74 | String ip = "Default"; 75 | 76 | for (String str : tabs) { 77 | int index = str.indexOf("@"); 78 | 79 | if (index > -1) { 80 | ip = str.substring(index + 1).trim(); 81 | } 82 | } 83 | String name = tabs[tabs.length - 1]; 84 | int index = name.indexOf('/'); 85 | 86 | if (index > -1) { 87 | name = name.substring(index + 1); 88 | } 89 | 90 | database = new Database(name, ip); 91 | 92 | connections.put(connection, database); 93 | } 94 | } else { 95 | return new Database("default", "default"); 96 | } 97 | } catch (Exception e) { 98 | log.error("parse database exception", e); 99 | } 100 | } 101 | return database; 102 | } 103 | 104 | @Data 105 | public class Database { 106 | private String name; 107 | private String ip; 108 | 109 | Database(String name, String ip) { 110 | this.name = name; 111 | this.ip = ip; 112 | } 113 | 114 | public String toString() { 115 | return name + '_' + ip; 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/datasource/druid/DruidInfoCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.datasource.druid; 2 | 3 | import com.github.seaframework.core.util.ClassUtil; 4 | import com.github.seaframework.core.util.NumberUtil; 5 | import com.github.seaframework.monitor.common.TagConst; 6 | import com.github.seaframework.monitor.dto.MetricDTO; 7 | import com.github.seaframework.monitor.heartbeat.datasource.DataSourceCollector; 8 | import com.github.seaframework.monitor.heartbeat.datasource.DatabaseParserHelper; 9 | 10 | import javax.management.ObjectName; 11 | import java.math.RoundingMode; 12 | import java.util.*; 13 | 14 | public class DruidInfoCollector extends DataSourceCollector { 15 | 16 | private final static String PREFIX_KEY = "druid"; 17 | 18 | public static final String DATASOURCE_NAME = "com.alibaba.druid.pool.DruidDataSource"; 19 | 20 | public static boolean exist() { 21 | return ClassUtil.load(DATASOURCE_NAME) != null; 22 | } 23 | 24 | private Map doCollect() { 25 | Map druidMonitorInfoMap = getDruidMonitorInfoMap(); 26 | Map map = new HashMap<>(); 27 | 28 | List metrics = new ArrayList<>(); 29 | for (Map.Entry entry : druidMonitorInfoMap.entrySet()) { 30 | String dataSourceName = entry.getKey(); 31 | DruidMonitorInfo value = entry.getValue(); 32 | 33 | Map tags = new HashMap<>(); 34 | tags.put(TagConst.SERVICE, dataSourceName); 35 | tags.put(TagConst.DB_TYPE, PREFIX_KEY); 36 | 37 | metrics.add(buildMetric("database.thread.pool.busy", value.getActiveCount(), tags)); 38 | metrics.add(buildMetric("database.thread.pool.total", value.getPoolingCount(), tags)); 39 | metrics.add(buildMetric("database.thread.pool.idle", value.getPoolingCount() - value.getActiveCount(), tags)); 40 | metrics.add(buildMetric("database.thread.pool.busy.percent", NumberUtil.divide(value.getActiveCount(), value.getMaxActive(), 3, RoundingMode.UP).doubleValue(), tags)); 41 | metrics.add(buildMetric("database.thread.pool.connect_error_count", value.getConnectErrorCount(), tags)); 42 | metrics.add(buildMetric("database.thread.pool.create_error_count", value.getCreateErrorCount(), tags)); 43 | metrics.add(buildMetric("database.thread.pool.error_count", value.getErrorCount(), tags)); 44 | } 45 | 46 | map.put("data", metrics); 47 | return map; 48 | } 49 | 50 | private DruidMonitorInfo getDruidMonitorInfo(ObjectName objectName) { 51 | DruidMonitorInfo druidMonitorInfo = new DruidMonitorInfo(); 52 | String jdbcUrl = getStringAttribute(objectName, "Url"); 53 | 54 | druidMonitorInfo.setJdbcUrl(jdbcUrl); 55 | druidMonitorInfo.setActiveCount(getIntegerAttribute(objectName, "ActiveCount", false)); 56 | druidMonitorInfo.setPoolingCount(getIntegerAttribute(objectName, "PoolingCount", false)); 57 | druidMonitorInfo.setMaxActive(getIntegerAttribute(objectName, "MaxActive", false)); 58 | 59 | druidMonitorInfo.setConnectErrorCount(getLongAttribute(objectName, "ConnectErrorCount", true)); 60 | druidMonitorInfo.setCreateErrorCount(getLongAttribute(objectName, "CreateErrorCount", true)); 61 | druidMonitorInfo.setErrorCount(getLongAttribute(objectName, "ErrorCount", true)); 62 | 63 | return druidMonitorInfo; 64 | } 65 | 66 | private Map getDruidMonitorInfoMap() { 67 | Map dataSourceInfoMap = new HashMap(); 68 | try { 69 | Hashtable table = new Hashtable(); 70 | 71 | table.put("type", "DruidDataSource"); 72 | table.put("id", "*"); 73 | 74 | ObjectName pooledDataSourceObjectName = new ObjectName("com.alibaba.druid", table); 75 | Set objectNameSet = mbeanServer.queryNames(pooledDataSourceObjectName, null); 76 | 77 | if (objectNameSet == null || objectNameSet.isEmpty()) { 78 | return dataSourceInfoMap; 79 | } 80 | 81 | Map datasources = new LinkedHashMap(); 82 | 83 | for (ObjectName objectName : objectNameSet) { 84 | DruidMonitorInfo info = getDruidMonitorInfo(objectName); 85 | String url = info.getJdbcUrl(); 86 | DatabaseParserHelper.Database datasource = databaseParser.parseDatabase(url); 87 | String key = getConnection(datasources, datasource.toString()); 88 | 89 | dataSourceInfoMap.put(key, info); 90 | } 91 | } catch (Exception e) { 92 | // ignore 93 | } 94 | return dataSourceInfoMap; 95 | } 96 | 97 | @Override 98 | public String getId() { 99 | return "datasource.druid"; 100 | } 101 | 102 | @Override 103 | public Map getProperties() { 104 | return doCollect(); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/datasource/druid/DruidMonitorInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.datasource.druid; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class DruidMonitorInfo { 7 | private String jdbcUrl; 8 | private int activeCount; 9 | private int poolingCount; 10 | private int maxActive; 11 | private int maxIdle; 12 | private int maxOpenPreparedStatements; 13 | private int maxPoolPreparedStatementPerConnectionSize; 14 | private long maxWait; 15 | private int maxWaitThreadCount; 16 | private int minIdle; 17 | private int queryTimeout; 18 | private int notEmptyWaitThreadCount; 19 | private int waitThreadCount; 20 | private long notEmptyWaitCount; 21 | private long notEmptyWaitMillis; 22 | private long startTransactionCount; 23 | private long recycleCount; 24 | private long rollbackCount; 25 | private long closeCount; 26 | private long closedPreparedStatementCount; 27 | private long commitCount; 28 | private long connectCount; 29 | private long connectErrorCount; 30 | private long createCount; 31 | private long createErrorCount; 32 | private long destroyCount; 33 | private long discardCount; 34 | private long dupCloseCount; 35 | private long errorCount; 36 | private long initialSize; 37 | private int lockQueueLength; 38 | private long createTimeSpanMillis; 39 | private long removeAbandonedCount; 40 | } 41 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/datasource/hikari/HikariInfoCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.datasource.hikari; 2 | 3 | import com.github.seaframework.core.util.ClassUtil; 4 | import com.github.seaframework.core.util.NumberUtil; 5 | import com.github.seaframework.monitor.common.TagConst; 6 | import com.github.seaframework.monitor.dto.MetricDTO; 7 | import com.github.seaframework.monitor.heartbeat.datasource.DataSourceCollector; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import javax.management.ObjectName; 11 | import java.math.RoundingMode; 12 | import java.util.*; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | /** 17 | * module name 18 | * 19 | * @author spy 20 | * @version 1.0 2020/4/17 21 | * @since 1.0 22 | */ 23 | @Slf4j 24 | public class HikariInfoCollector extends DataSourceCollector { 25 | private final static String PREFIX_KEY = "hikari"; 26 | public static final String DATASOURCE_NAME = "com.zaxxer.hikari.HikariDataSource"; 27 | 28 | public static boolean exist() { 29 | return ClassUtil.load(DATASOURCE_NAME) != null; 30 | } 31 | 32 | private Map doCollect() { 33 | Map map = new LinkedHashMap<>(); 34 | Map monitorInfoMap = getMonitorInfoMap(); 35 | List metrics = new ArrayList<>(); 36 | 37 | for (Map.Entry entry : monitorInfoMap.entrySet()) { 38 | String dataSourceName = entry.getKey(); 39 | HikariMonitorInfo value = entry.getValue(); 40 | 41 | Map tags = new HashMap<>(); 42 | tags.put(TagConst.SERVICE, dataSourceName); 43 | tags.put(TagConst.DB_TYPE, PREFIX_KEY); 44 | 45 | metrics.add(buildMetric("database.thread.pool.busy", value.getActiveConnections(), tags)); 46 | metrics.add(buildMetric("database.thread.pool.total", value.getTotalConnections(), tags)); 47 | metrics.add(buildMetric("database.thread.pool.idle", value.getIdleConnections(), tags)); 48 | metrics.add(buildMetric("database.thread.pool.waiting", value.getThreadsAwaitingConnection(), tags)); 49 | metrics.add(buildMetric("database.thread.pool.busy.percent", NumberUtil.divide(value.getActiveConnections(), value.getMaximumPoolSize(), 3, RoundingMode.UP).doubleValue(), tags)); 50 | } 51 | 52 | return map; 53 | } 54 | 55 | private HikariMonitorInfo getPoolInfo(ObjectName objectName) { 56 | HikariMonitorInfo monitorInfo = new HikariMonitorInfo(); 57 | monitorInfo.setName(getMatchValue(objectName.getCanonicalName())); 58 | 59 | monitorInfo.setActiveConnections(getIntegerAttribute(objectName, "ActiveConnections", false)); 60 | monitorInfo.setIdleConnections(getIntegerAttribute(objectName, "IdleConnections", false)); 61 | monitorInfo.setThreadsAwaitingConnection(getIntegerAttribute(objectName, "ThreadsAwaitingConnection", false)); 62 | monitorInfo.setTotalConnections(getIntegerAttribute(objectName, "TotalConnections", false)); 63 | 64 | return monitorInfo; 65 | } 66 | 67 | private HikariMonitorInfo getPoolConfigInfo(ObjectName objectName, HikariMonitorInfo monitorInfo) { 68 | monitorInfo.setMaximumPoolSize(getIntegerAttribute(objectName, "MaximumPoolSize", false)); 69 | return monitorInfo; 70 | } 71 | 72 | private Map getMonitorInfoMap() { 73 | Map dataSourceInfoMap = new LinkedHashMap<>(); 74 | 75 | try { 76 | Hashtable table = new Hashtable<>(); 77 | table.put("type", "Pool (*"); 78 | 79 | ObjectName poolObjectName = new ObjectName("com.zaxxer.hikari", table); 80 | Set objectNameSet = mbeanServer.queryNames(poolObjectName, null); 81 | 82 | if (objectNameSet == null || objectNameSet.isEmpty()) { 83 | return dataSourceInfoMap; 84 | } 85 | 86 | for (ObjectName objectName : objectNameSet) { 87 | HikariMonitorInfo info = getPoolInfo(objectName); 88 | dataSourceInfoMap.put(info.getName(), info); 89 | } 90 | 91 | table = new Hashtable<>(); 92 | table.put("type", "PoolConfig (*"); 93 | 94 | ObjectName poolConfigObjectName = new ObjectName("com.zaxxer.hikari", table); 95 | Set configObjectNameSet = mbeanServer.queryNames(poolConfigObjectName, null); 96 | 97 | if (configObjectNameSet == null || configObjectNameSet.isEmpty()) { 98 | return dataSourceInfoMap; 99 | } 100 | 101 | for (ObjectName objectName : configObjectNameSet) { 102 | String key = getMatchValue(objectName.getCanonicalName()); 103 | 104 | if (dataSourceInfoMap.containsKey(key)) { 105 | HikariMonitorInfo info = dataSourceInfoMap.get(key); 106 | getPoolConfigInfo(objectName, info); 107 | } 108 | } 109 | } catch (Exception ignored) { 110 | } 111 | return dataSourceInfoMap; 112 | } 113 | 114 | @Override 115 | public String getId() { 116 | return "datasource.hikari"; 117 | } 118 | 119 | @Override 120 | public Map getProperties() { 121 | return doCollect(); 122 | } 123 | 124 | Pattern pattern = Pattern.compile("(?<=\\()(.+?)(?=\\))"); 125 | 126 | private String getMatchValue(String name) { 127 | try { 128 | Matcher matcher = pattern.matcher(name); 129 | while (matcher.find()) { 130 | return matcher.group(); 131 | } 132 | } catch (Exception e) { 133 | log.error("match error", e); 134 | } 135 | return name; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/datasource/hikari/HikariMonitorInfo.java: -------------------------------------------------------------------------------- 1 | 2 | package com.github.seaframework.monitor.heartbeat.datasource.hikari; 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class HikariMonitorInfo { 8 | private String name; 9 | 10 | private int activeConnections; 11 | private int idleConnections; 12 | private int threadsAwaitingConnection; 13 | private int totalConnections; 14 | 15 | // pool config 16 | private int minimumIdle; 17 | private int maximumPoolSize; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/dubbo/AbstractDubboThreadPoolHeartbeat.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.dubbo; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.github.seaframework.core.util.*; 6 | import com.github.seaframework.monitor.common.TagConst; 7 | import com.github.seaframework.monitor.dto.MetricDTO; 8 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | import java.lang.reflect.Method; 12 | import java.math.RoundingMode; 13 | import java.util.ArrayList; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | /** 19 | * module name 20 | * 21 | * @author spy 22 | * @version 1.0 2020/4/3 23 | * @since 1.0 24 | */ 25 | @Slf4j 26 | public abstract class AbstractDubboThreadPoolHeartbeat extends AbstractCollector { 27 | 28 | private static final double MAX_THRESHOLD_VALUE = 0.9; 29 | 30 | public abstract String getThreadPoolName(); 31 | 32 | protected Map doStatics() { 33 | String threadPoolName = getThreadPoolName(); 34 | if (StringUtil.isEmpty(threadPoolName)) { 35 | return MapUtil.empty(); 36 | } 37 | 38 | try { 39 | Class clazz = ClassUtil.load(getThreadPoolName()); 40 | if (clazz == null) { 41 | return MapUtil.empty(); 42 | } 43 | Method check = clazz.getMethod("check"); 44 | Object invoke = check.invoke(clazz.newInstance()); 45 | 46 | // parse message 47 | //{"level":"OK","message":"Pool status:OK, max:200, core:200, largest:27, active:0, task:27, service port: 20888"} 48 | // message=@String[Pool status:OK, max:200, core:200, largest:200, active:0, task:12961, service port: 20880;Pool status:OK, max:2147483647, core:0, largest:1, active:0, task:2824, service port: 7070], 49 | JSONObject jsonObj = JSON.parseObject(JSON.toJSONString(invoke)); 50 | String level = jsonObj.getString("level"); 51 | String msg = jsonObj.getString("message"); 52 | 53 | if (StringUtil.isEmpty(level) || EqualUtil.isEq(level, "UNKNOWN", false) || StringUtil.isEmpty(msg)) { 54 | return MapUtil.empty(); 55 | } 56 | 57 | List values = StringUtil.splitToList(msg, ';'); 58 | if (ListUtil.isEmpty(values)) { 59 | return MapUtil.empty(); 60 | } 61 | 62 | List data = new ArrayList<>(); 63 | for (int i = 0; i < values.size(); i++) { 64 | String message = values.get(i); 65 | List items = StringUtil.splitToList(message, ','); 66 | if (ListUtil.isEmpty(items)) { 67 | continue; 68 | } 69 | Map valueMap = new HashMap<>(items.size()); 70 | 71 | for (int j = 0; j < items.size(); j++) { 72 | String item = items.get(j); 73 | String[] valueArray = StringUtil.split(item, ':'); 74 | if (valueArray == null || valueArray.length != 2) { 75 | continue; 76 | } 77 | valueMap.put(valueArray[0].trim(), valueArray[1].trim()); 78 | } 79 | 80 | String port = MapUtil.getString(valueMap, "service port", ""); 81 | if (StringUtil.isEmpty(port)) { 82 | log.warn("service port is null, skip it"); 83 | continue; 84 | } 85 | Map tags = new HashMap<>(1, 1); 86 | tags.put(TagConst.PORT, port); 87 | // report 88 | double max = MapUtil.getDoubleValue(valueMap, "max", 0); 89 | double active = MapUtil.getDoubleValue(valueMap, "active", 0); 90 | double activePercent = NumberUtil.divide(active, max, 3, RoundingMode.UP).doubleValue(); 91 | 92 | data.add(buildMetric("dubbo.thread.pool.max", max, tags)); 93 | data.add(buildMetric("dubbo.thread.pool.core", MapUtil.getDoubleValue(valueMap, "core", 0), tags)); 94 | data.add(buildMetric("dubbo.thread.pool.largest", MapUtil.getDoubleValue(valueMap, "largest", 0), tags)); 95 | data.add(buildMetric("dubbo.thread.pool.active", active, tags)); 96 | data.add(buildMetric("dubbo.thread.pool.task", MapUtil.getDoubleValue(valueMap, "task", 0), tags)); 97 | data.add(buildMetric("dubbo.thread.pool.active.percent", activePercent, tags)); 98 | 99 | if (max < Integer.MAX_VALUE) { 100 | checkDumpStack(activePercent); 101 | } 102 | } 103 | 104 | Map retMap = new HashMap<>(); 105 | retMap.put("data", data); 106 | 107 | return retMap; 108 | } catch (Exception e) { 109 | log.info("fail to report ", e); 110 | } 111 | 112 | return MapUtil.empty(); 113 | } 114 | 115 | @Override 116 | public String getId() { 117 | return "dubbo.thread.pool"; 118 | } 119 | 120 | @Override 121 | public Map getProperties() { 122 | return doStatics(); 123 | } 124 | 125 | 126 | protected void checkDumpStack(double activePercent) { 127 | if (activePercent >= MAX_THRESHOLD_VALUE) { 128 | log.warn("begin dump java stack"); 129 | Thread t = new Thread(() -> JvmUtil.dumpStackLimiter()); 130 | t.start(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/dubbo/DubboLegacyThreadPoolHeartbeat.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.dubbo; 2 | 3 | import com.github.seaframework.core.util.ClassUtil; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | /** 7 | * module name 8 | * 9 | * @author spy 10 | * @version 1.0 2020/4/3 11 | * @since 1.0 12 | */ 13 | @Slf4j 14 | public class DubboLegacyThreadPoolHeartbeat extends AbstractDubboThreadPoolHeartbeat { 15 | 16 | private static final String THREAD_POOL_CHECK_CLASS = "com.alibaba.dubbo.rpc.protocol.dubbo.status.ThreadPoolStatusChecker"; 17 | 18 | public static boolean exist() { 19 | return ClassUtil.load(THREAD_POOL_CHECK_CLASS) != null; 20 | } 21 | 22 | @Override 23 | public String getThreadPoolName() { 24 | return THREAD_POOL_CHECK_CLASS; 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/dubbo/DubboThreadPoolHeartbeat.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.dubbo; 2 | 3 | import com.github.seaframework.core.util.ClassUtil; 4 | import com.github.seaframework.core.util.ListUtil; 5 | import com.github.seaframework.core.util.MapUtil; 6 | import com.github.seaframework.core.util.ReflectUtil; 7 | import com.github.seaframework.monitor.common.TagConst; 8 | import com.github.seaframework.monitor.dto.MetricDTO; 9 | import com.github.seaframework.monitor.util.ThreadPoolUtil; 10 | import com.github.seaframework.monitor.vo.ThreadPoolStatus; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.apache.dubbo.common.constants.CommonConstants; 13 | import org.apache.dubbo.common.extension.ExtensionLoader; 14 | import org.apache.dubbo.common.threadpool.manager.DefaultExecutorRepository; 15 | import org.apache.dubbo.common.threadpool.manager.ExecutorRepository; 16 | 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.concurrent.ConcurrentMap; 22 | import java.util.concurrent.ExecutorService; 23 | import java.util.concurrent.ThreadPoolExecutor; 24 | 25 | /** 26 | * module name 27 | * 28 | * @author spy 29 | * @version 1.0 2020/4/3 30 | * @since 1.0 31 | */ 32 | @Slf4j 33 | public class DubboThreadPoolHeartbeat extends AbstractDubboThreadPoolHeartbeat { 34 | 35 | private static final String THREAD_POOL_CHECK_CLASS = "org.apache.dubbo.rpc.protocol.dubbo.status.ThreadPoolStatusChecker"; 36 | 37 | public static boolean exist() { 38 | return ClassUtil.load(THREAD_POOL_CHECK_CLASS) != null; 39 | } 40 | 41 | @Override 42 | public String getThreadPoolName() { 43 | return THREAD_POOL_CHECK_CLASS; 44 | } 45 | 46 | @Override 47 | protected Map doStatics() { 48 | 49 | try { 50 | ExecutorRepository executorRepository = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension(); 51 | 52 | if (executorRepository instanceof DefaultExecutorRepository) { 53 | DefaultExecutorRepository defaultExecutorRepository = (DefaultExecutorRepository) executorRepository; 54 | 55 | //String componentKey = EXECUTOR_SERVICE_COMPONENT_KEY; 56 | // if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) { 57 | // componentKey = CONSUMER_SIDE; 58 | // } 59 | // data的key是固定的,要么是 EXECUTOR_SERVICE_COMPONENT_KEY 要么是 CONSUMER_SIDE 60 | ConcurrentMap> data = (ConcurrentMap>) ReflectUtil.read(defaultExecutorRepository, "data"); 61 | 62 | //provider 63 | ConcurrentMap executors = data.get(CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY); 64 | if (executors != null) { 65 | List metrics = new ArrayList<>(); 66 | 67 | executors.forEach((port, executor) -> { 68 | if (executor instanceof ThreadPoolExecutor) { 69 | ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor; 70 | ThreadPoolStatus status = ThreadPoolUtil.getStatus(tpe); 71 | 72 | Map tags = new HashMap<>(1, 1); 73 | tags.put(TagConst.PORT, "" + port); 74 | 75 | metrics.add(buildMetric("dubbo.thread.pool.max", status.getMax(), tags)); 76 | metrics.add(buildMetric("dubbo.thread.pool.core", status.getCore(), tags)); 77 | metrics.add(buildMetric("dubbo.thread.pool.largest", status.getLargest(), tags)); 78 | metrics.add(buildMetric("dubbo.thread.pool.active", status.getActive(), tags)); 79 | metrics.add(buildMetric("dubbo.thread.pool.task", status.getTask(), tags)); 80 | metrics.add(buildMetric("dubbo.thread.pool.active.percent", status.getActivePercent(), tags)); 81 | 82 | if (status.getMax() < Integer.MAX_VALUE) { 83 | checkDumpStack(status.getActivePercent()); 84 | } 85 | } 86 | }); 87 | if (ListUtil.isNotEmpty(metrics)) { 88 | Map retMap = new HashMap<>(1); 89 | retMap.put("data", metrics); 90 | return retMap; 91 | } 92 | 93 | } 94 | 95 | } else { 96 | log.warn("unchecked thread pool implement. Plz contact developer."); 97 | } 98 | 99 | } catch (Exception e) { 100 | log.error("fail to collector apache dubbo thread pool info.", e); 101 | } 102 | 103 | return MapUtil.empty(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/http/HttpStats.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.http; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | import java.util.concurrent.atomic.AtomicLong; 5 | 6 | public class HttpStats { 7 | private static HttpStats current = null; 8 | private AtomicInteger httpStatus400Count = new AtomicInteger(); 9 | private AtomicInteger httpStatus500Count = new AtomicInteger(); 10 | private AtomicInteger httpCount = new AtomicInteger(); 11 | private AtomicLong httpTimeSum = new AtomicLong(); 12 | 13 | public static HttpStats currentStatsHolder() { 14 | if (null == current) { 15 | synchronized (HttpStats.class) { 16 | if (null == current) { 17 | current = new HttpStats(); 18 | } 19 | } 20 | } 21 | return current; 22 | } 23 | 24 | public static synchronized HttpStats getAndReset() { 25 | HttpStats tmp = new HttpStats(); 26 | HttpStats old = currentStatsHolder(); 27 | current = tmp; 28 | return old; 29 | } 30 | 31 | private HttpStats() { 32 | } 33 | 34 | public void doRequestStats(long mills, int status) { 35 | try { 36 | if (is400(status)) { 37 | httpStatus400Count.incrementAndGet(); 38 | } else if (is500(status)) { 39 | httpStatus500Count.incrementAndGet(); 40 | } 41 | httpCount.incrementAndGet(); 42 | httpTimeSum.addAndGet(mills); 43 | } catch (Exception e) { 44 | // ignore 45 | } 46 | } 47 | 48 | public int getHttpCount() { 49 | return httpCount.get(); 50 | } 51 | 52 | public int getHttpMeantime() { 53 | long meantime = 0 == httpCount.get() ? 0 : (httpTimeSum.get() / httpCount.get()); 54 | return (int) meantime; 55 | } 56 | 57 | public int getHttpStatus400Count() { 58 | return httpStatus400Count.get(); 59 | } 60 | 61 | public int getHttpStatus500Count() { 62 | return httpStatus500Count.get(); 63 | } 64 | 65 | private boolean is400(int status) { 66 | return status >= 400 && status < 500; 67 | } 68 | 69 | private boolean is500(int status) { 70 | return status >= 500; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/http/HttpStatsCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.http; 2 | 3 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * 应该没有使用 10 | * 11 | * @author spy 12 | * @version 1.0 13 | */ 14 | public class HttpStatsCollector extends AbstractCollector { 15 | 16 | private Map doClassLoadingCollect() { 17 | Map map = new HashMap<>(4); 18 | HttpStats stats = HttpStats.getAndReset(); 19 | 20 | map.put("http.count", stats.getHttpCount()); 21 | map.put("http.meantime", stats.getHttpMeantime()); 22 | map.put("http.status400.count", stats.getHttpStatus400Count()); 23 | map.put("http.status500.count", stats.getHttpStatus500Count()); 24 | return map; 25 | } 26 | 27 | @Override 28 | public String getId() { 29 | return "http.status"; 30 | } 31 | 32 | @Override 33 | public Map getProperties() { 34 | return doClassLoadingCollect(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/jvm/ClassLoadingInfoCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.jvm; 2 | 3 | 4 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 5 | 6 | import java.lang.management.ClassLoadingMXBean; 7 | import java.lang.management.ManagementFactory; 8 | import java.util.LinkedHashMap; 9 | import java.util.Map; 10 | 11 | public class ClassLoadingInfoCollector extends AbstractCollector { 12 | 13 | private Map doClassLoadingCollect() { 14 | ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean(); 15 | Map map = new LinkedHashMap<>(); 16 | 17 | map.put("jvm.classloading.loaded.count", classLoadingMXBean.getLoadedClassCount()); 18 | map.put("jvm.classloading.totalloaded.count", classLoadingMXBean.getTotalLoadedClassCount()); 19 | map.put("jvm.classloading.unloaded.count", classLoadingMXBean.getUnloadedClassCount()); 20 | 21 | return map; 22 | } 23 | 24 | @Override 25 | public String getId() { 26 | return "jvm.classloading"; 27 | } 28 | 29 | @Override 30 | public Map getProperties() { 31 | return doClassLoadingCollect(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/jvm/ThreadInfoCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.jvm; 2 | 3 | 4 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 5 | 6 | import java.lang.management.ManagementFactory; 7 | import java.lang.management.ThreadInfo; 8 | import java.lang.management.ThreadMXBean; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | 12 | public class ThreadInfoCollector extends AbstractCollector { 13 | 14 | private int countThreadsByPrefix(ThreadInfo[] threads, String... prefixes) { 15 | int count = 0; 16 | 17 | for (ThreadInfo thread : threads) { 18 | if (thread != null) { 19 | for (String prefix : prefixes) { 20 | if (String.valueOf(thread.getThreadName()).startsWith(prefix)) { 21 | count++; 22 | } 23 | } 24 | } 25 | } 26 | 27 | return count; 28 | } 29 | 30 | private int countThreadsBySubstring(ThreadInfo[] threads, String... substrings) { 31 | int count = 0; 32 | 33 | for (ThreadInfo thread : threads) { 34 | if (thread != null) { 35 | for (String str : substrings) { 36 | if (String.valueOf(thread.getThreadName()).contains(str)) { 37 | count++; 38 | } 39 | } 40 | } 41 | } 42 | 43 | return count; 44 | } 45 | 46 | private Map doThreadCollect() { 47 | final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); 48 | Map map = new LinkedHashMap<>(); 49 | map.put("jvm.thread.count", threadBean.getThreadCount()); 50 | map.put("jvm.thread.daemon.count", threadBean.getDaemonThreadCount()); 51 | map.put("jvm.thread.totalstarted.count", threadBean.getTotalStartedThreadCount()); 52 | ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadBean.getAllThreadIds()); 53 | 54 | int newThreadCount = 0; 55 | int runnableThreadCount = 0; 56 | int blockedThreadCount = 0; 57 | int waitThreadCount = 0; 58 | int timeWaitThreadCount = 0; 59 | int terminatedThreadCount = 0; 60 | 61 | if (threadInfos != null) { 62 | for (ThreadInfo threadInfo : threadInfos) { 63 | if (threadInfo != null) { 64 | switch (threadInfo.getThreadState()) { 65 | case NEW: 66 | newThreadCount++; 67 | break; 68 | case RUNNABLE: 69 | runnableThreadCount++; 70 | break; 71 | case BLOCKED: 72 | blockedThreadCount++; 73 | break; 74 | case WAITING: 75 | waitThreadCount++; 76 | break; 77 | case TIMED_WAITING: 78 | timeWaitThreadCount++; 79 | break; 80 | case TERMINATED: 81 | terminatedThreadCount++; 82 | break; 83 | default: 84 | break; 85 | } 86 | } else { 87 | /** 88 | * If a thread of a given ID is not alive or does not exist, the corresponding element in the returned array will, 89 | * contain null,because is mut exist ,so the thread is terminated 90 | */ 91 | terminatedThreadCount++; 92 | } 93 | } 94 | } 95 | 96 | map.put("jvm.thread.new.count", newThreadCount); 97 | map.put("jvm.thread.runnable.count", runnableThreadCount); 98 | map.put("jvm.thread.blocked.count", blockedThreadCount); 99 | map.put("jvm.thread.waiting.count", waitThreadCount); 100 | map.put("jvm.thread.time_waiting.count", timeWaitThreadCount); 101 | map.put("jvm.thread.terminated.count", terminatedThreadCount); 102 | 103 | long[] ids = threadBean.findDeadlockedThreads(); 104 | 105 | map.put("jvm.thread.deadlock.count", ids == null ? 0 : ids.length); 106 | 107 | if (threadInfos != null) { 108 | int tomcatThreadsCount = countThreadsByPrefix(threadInfos, "http-", "catalina-exec-"); 109 | int jettyThreadsCount = countThreadsBySubstring(threadInfos, "@qtp"); 110 | map.put("jvm.thread.http.count", tomcatThreadsCount + jettyThreadsCount); 111 | } 112 | 113 | return map; 114 | } 115 | 116 | @Override 117 | public String getId() { 118 | return "jvm.thread"; 119 | } 120 | 121 | @Override 122 | public Map getProperties() { 123 | return doThreadCollect(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/redis/AbstractRedisStatsCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.redis; 2 | 3 | import com.github.seaframework.core.util.MapUtil; 4 | import com.github.seaframework.core.util.NumberUtil; 5 | import com.github.seaframework.monitor.common.MonitorConst; 6 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.math.RoundingMode; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * module name 15 | * 16 | * @author spy 17 | * @version 1.0 2020/4/23 18 | * @since 1.0 19 | */ 20 | @Slf4j 21 | public abstract class AbstractRedisStatsCollector extends AbstractCollector { 22 | @Override 23 | public String getId() { 24 | return "sea.redis.stats.collector"; 25 | } 26 | 27 | public abstract RedisMonitorInfo getRedisMonitorInfo(); 28 | 29 | // for single 30 | @Override 31 | public Map getProperties() { 32 | 33 | RedisMonitorInfo redisMonitorInfo = getRedisMonitorInfo(); 34 | 35 | if (redisMonitorInfo == null) { 36 | return MapUtil.empty(); 37 | } 38 | Map map = new HashMap<>(); 39 | 40 | map.put(MonitorConst.METRIC_REDIS_ACTIVE_COUNT, redisMonitorInfo.getActiveCount()); 41 | map.put(MonitorConst.METRIC_REDIS_IDLE_COUNT, redisMonitorInfo.getIdleCount()); 42 | map.put(MonitorConst.METRIC_REDIS_WAITER_COUNT, redisMonitorInfo.getWaiterCount()); 43 | map.put(MonitorConst.METRIC_REDIS_TOTAL_COUNT, redisMonitorInfo.getTotalCount()); 44 | map.put(MonitorConst.METRIC_REDIS_ACTIVE_PERCENT, NumberUtil.divide(redisMonitorInfo.getActiveCount(), redisMonitorInfo.getTotalCount(), 3, RoundingMode.UP)); 45 | 46 | return map; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/redis/RedisMonitorInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.redis; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * module name 7 | * 8 | * @author spy 9 | * @version 1.0 2020/4/23 10 | * @since 1.0 11 | */ 12 | @Data 13 | public class RedisMonitorInfo { 14 | // 实例名 15 | private String serviceName; 16 | 17 | // current active count 18 | private int activeCount; 19 | // idle count 20 | private int idleCount; 21 | // waiter count 22 | private int waiterCount; 23 | 24 | private int totalCount; 25 | } 26 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/sys/SysAliveCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.sys; 2 | 3 | import com.github.seaframework.monitor.common.MonitorConst; 4 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * module name 12 | * 13 | * @author spy 14 | * @version 1.0 2020/4/12 15 | * @since 1.0 16 | */ 17 | @Slf4j 18 | public class SysAliveCollector extends AbstractCollector { 19 | @Override 20 | public String getId() { 21 | return "sea.sys.alive"; 22 | } 23 | 24 | @Override 25 | public Map getProperties() { 26 | Map map = new HashMap<>(1); 27 | map.put(MonitorConst.METRIC_SYS_ALIVE, 1); 28 | return map; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/tomcat/TomcatHttpStatsCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.tomcat; 2 | 3 | import com.github.seaframework.monitor.common.MonitorCommon; 4 | import com.github.seaframework.monitor.common.TagConst; 5 | import com.github.seaframework.monitor.dto.MetricDTO; 6 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 7 | import com.github.seaframework.monitor.util.JMXUtil; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import javax.management.MBeanServer; 11 | import javax.management.ObjectName; 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * tomcat http stats collector 19 | * 20 | * @author spy 21 | * @version 1.0 2020/5/5 22 | * @since 1.0 23 | */ 24 | @Slf4j 25 | public class TomcatHttpStatsCollector extends AbstractCollector { 26 | private MBeanServer mbeanServer; 27 | private ObjectName objectName; 28 | 29 | public TomcatHttpStatsCollector() { 30 | objectName = JMXUtil.createObjectName("*:type=GlobalRequestProcessor,*"); 31 | mbeanServer = JMXUtil.getMBeanServer(); 32 | } 33 | 34 | public static boolean exist() { 35 | return MonitorCommon.isTomcatContainer(); 36 | } 37 | 38 | @Override 39 | public String getId() { 40 | return "tomcat.http"; 41 | } 42 | 43 | @Override 44 | public Map getProperties() { 45 | if (log.isDebugEnabled()) { 46 | log.debug("collect tomcat http info"); 47 | } 48 | // collect thread metrics 49 | Map map = new HashMap<>(); 50 | ObjectName[] connectorNames = JMXUtil.getObjectNames(objectName); 51 | 52 | 53 | List metrics = new ArrayList<>(); 54 | for (ObjectName connectorName : connectorNames) { 55 | String name = ObjectName.unquote(connectorName.getKeyProperty("name")); 56 | // 基本不使用的协议 57 | if (name.startsWith("ajp")) { 58 | continue; 59 | } 60 | 61 | Map tags = new HashMap<>(); 62 | tags.put(TagConst.SERVICE, name); 63 | 64 | try { 65 | int requestCount = (Integer) mbeanServer.getAttribute(connectorName, "requestCount"); 66 | metrics.add(buildMetric("tomcat.http.request.count", requestCount, tags)); 67 | 68 | int errorCount = (Integer) mbeanServer.getAttribute(connectorName, "errorCount"); 69 | metrics.add(buildMetric("tomcat.http.error.count", errorCount, tags)); 70 | 71 | long processingTime = (Long) mbeanServer.getAttribute(connectorName, "processingTime"); 72 | metrics.add(buildMetric("tomcat.http.processing.time", processingTime, tags)); 73 | 74 | long maxTime = (Long) mbeanServer.getAttribute(connectorName, "maxTime"); 75 | metrics.add(buildMetric("tomcat.http.max.time", maxTime, tags)); 76 | 77 | long bytesReceived = (Long) mbeanServer.getAttribute(connectorName, "bytesReceived"); 78 | metrics.add(buildMetric("tomcat.http.bytes.received", bytesReceived, tags)); 79 | 80 | long bytesSent = (Long) mbeanServer.getAttribute(connectorName, "bytesSent"); 81 | metrics.add(buildMetric("tomcat.http.bytes.sent", bytesSent, tags)); 82 | 83 | } catch (Exception e) { 84 | log.error("Exception occur when getting connector global stats: ", e); 85 | } 86 | 87 | } 88 | map.put("data", metrics); 89 | return map; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/heartbeat/tomcat/TomcatThreadPoolStatsCollector.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.heartbeat.tomcat; 2 | 3 | import com.github.seaframework.core.util.EqualUtil; 4 | import com.github.seaframework.core.util.JvmUtil; 5 | import com.github.seaframework.core.util.NumberUtil; 6 | import com.github.seaframework.core.util.StringUtil; 7 | import com.github.seaframework.monitor.common.MonitorCommon; 8 | import com.github.seaframework.monitor.common.TagConst; 9 | import com.github.seaframework.monitor.dto.MetricDTO; 10 | import com.github.seaframework.monitor.heartbeat.AbstractCollector; 11 | import com.github.seaframework.monitor.util.JMXUtil; 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | import javax.management.MBeanServer; 15 | import javax.management.ObjectName; 16 | import java.math.RoundingMode; 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | /** 23 | * tomcat thread pool stats collector 24 | * 25 | * @author spy 26 | * @version 1.0 2020/5/3 27 | * @since 1.0 28 | */ 29 | @Slf4j 30 | public class TomcatThreadPoolStatsCollector extends AbstractCollector { 31 | private MBeanServer mbeanServer; 32 | private ObjectName objectName; 33 | 34 | private static final String[] metricNames = { 35 | "busy_count", 36 | "total_count", 37 | "min_pool_size", 38 | "max_pool_size", 39 | "thread_pool_queue_size" 40 | }; 41 | 42 | public TomcatThreadPoolStatsCollector() { 43 | objectName = JMXUtil.createObjectName("*:type=ThreadPool,*"); 44 | mbeanServer = JMXUtil.getMBeanServer(); 45 | } 46 | 47 | public static boolean exist() { 48 | return MonitorCommon.isTomcatContainer(); 49 | } 50 | 51 | 52 | @Override 53 | public String getId() { 54 | return "tomcat.stats"; 55 | } 56 | 57 | @Override 58 | public Map getProperties() { 59 | if (log.isDebugEnabled()) { 60 | log.debug("collect tomcat stats info"); 61 | } 62 | // collect thread metrics 63 | Map map = new HashMap<>(); 64 | ObjectName[] connectorNames = JMXUtil.getObjectNames(objectName); 65 | 66 | List metrics = new ArrayList<>(); 67 | for (ObjectName connectorName : connectorNames) { 68 | // only check one 69 | String subType = connectorName.getKeyProperty("subType"); 70 | if (StringUtil.isNotEmpty(subType)) { 71 | continue; 72 | } 73 | if (!isTomcatServer(connectorName.getDomain())) { 74 | continue; 75 | } 76 | 77 | String name = ObjectName.unquote(connectorName.getKeyProperty("name")); 78 | // 基本不使用的协议 79 | if (name.startsWith("ajp")) { 80 | continue; 81 | } 82 | 83 | Map tags = new HashMap<>(); 84 | tags.put(TagConst.SERVICE, name); 85 | try { 86 | int currentThreadsBusy = (Integer) mbeanServer.getAttribute(connectorName, "currentThreadsBusy"); 87 | metrics.add(buildMetric("tomcat.thread.pool.busy", currentThreadsBusy, tags)); 88 | 89 | int currentThreadCount = (Integer) mbeanServer.getAttribute(connectorName, "currentThreadCount"); 90 | metrics.add(buildMetric("tomcat.thread.pool.current", currentThreadCount, tags)); 91 | 92 | int minSpareThreads = (Integer) mbeanServer.getAttribute(connectorName, "minSpareThreads"); 93 | metrics.add(buildMetric("tomcat.thread.pool.min.spare", minSpareThreads, tags)); 94 | 95 | int maxThreads = (Integer) mbeanServer.getAttribute(connectorName, "maxThreads"); 96 | metrics.add(buildMetric("tomcat.thread.pool.max", maxThreads, tags)); 97 | 98 | double busyPercent = NumberUtil.divide(currentThreadsBusy, maxThreads, 3, RoundingMode.UP).doubleValue(); 99 | metrics.add(buildMetric("tomcat.thread.pool.busy.percent", busyPercent, tags)); 100 | // should be only one stat object there 101 | checkDumpStack(busyPercent); 102 | 103 | } catch (Exception e) { 104 | log.error("Exception occur when getting connector global stats: ", e); 105 | } 106 | 107 | // cannot visit for now 108 | // try { 109 | // int queueSize = (Integer) mbeanServer.getAttribute(connectorName, "threadPoolTaskQueueSize"); 110 | // metrics.add(buildMetric("tomcat.thread.pool.queue", queueSize, tags)); 111 | // } catch (Exception e) { 112 | // log.error("Exception occur when getting connector global stats: ", e); 113 | // } 114 | 115 | } 116 | map.put("data", metrics); 117 | return map; 118 | } 119 | 120 | private boolean isTomcatServer(String domain) { 121 | if (StringUtil.isEmpty(domain)) { 122 | return false; 123 | } 124 | 125 | return EqualUtil.isEq("tomcat", domain, false) || 126 | EqualUtil.isEq("catalina", domain, false); 127 | } 128 | 129 | private static final double MAX_THRESHOLD_VALUE = 0.9; 130 | 131 | private void checkDumpStack(double activePercent) { 132 | if (activePercent >= MAX_THRESHOLD_VALUE) { 133 | log.warn("begin dump java stack"); 134 | Thread t = new Thread(() -> JvmUtil.dumpStackLimiter()); 135 | t.start(); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/log4j/Log4j2Appender.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.log4j; 2 | 3 | import com.github.seaframework.monitor.SeaMonitor; 4 | import com.github.seaframework.monitor.enums.CounterEnum; 5 | import org.apache.logging.log4j.Level; 6 | import org.apache.logging.log4j.core.Filter; 7 | import org.apache.logging.log4j.core.Layout; 8 | import org.apache.logging.log4j.core.LogEvent; 9 | import org.apache.logging.log4j.core.appender.AbstractAppender; 10 | import org.apache.logging.log4j.core.appender.AppenderLoggingException; 11 | import org.apache.logging.log4j.core.config.plugins.Plugin; 12 | import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 13 | import org.apache.logging.log4j.core.config.plugins.PluginElement; 14 | import org.apache.logging.log4j.core.config.plugins.PluginFactory; 15 | import org.apache.logging.log4j.core.layout.PatternLayout; 16 | 17 | import java.io.Serializable; 18 | 19 | @Plugin(name = "SeaMonitorAppender", category = "Core", elementType = "appender", printObject = true) 20 | public class Log4j2Appender extends AbstractAppender { 21 | 22 | private static final long serialVersionUID = 2705802038361151598L; 23 | 24 | private Log4j2Appender(String name, Filter filter, Layout layout, 25 | final boolean ignoreExceptions) { 26 | super(name, filter, layout, ignoreExceptions); 27 | } 28 | 29 | @Override 30 | public void append(LogEvent event) { 31 | try { 32 | Level level = event.getLevel(); 33 | 34 | if (level.isMoreSpecificThan(Level.ERROR)) { 35 | logError(event); 36 | } 37 | } catch (Exception ex) { 38 | if (!ignoreExceptions()) { 39 | throw new AppenderLoggingException(ex); 40 | } 41 | } 42 | } 43 | 44 | @PluginFactory 45 | public static Log4j2Appender createAppender(@PluginAttribute("name") String name, 46 | @PluginElement("Layout") Layout layout, @PluginElement("Filter") final Filter filter, 47 | @PluginAttribute("otherAttribute") String otherAttribute) { 48 | if (name == null) { 49 | return null; 50 | } 51 | if (layout == null) { 52 | layout = PatternLayout.createDefaultLayout(); 53 | } 54 | return new Log4j2Appender(name, filter, layout, true); 55 | } 56 | 57 | private void logError(LogEvent event) { 58 | // ThrowableProxy info = event.getThrownProxy(); 59 | // 60 | // if (info != null) { 61 | SeaMonitor.logCount(CounterEnum.SYS_LOG_COUNT.getKey()); 62 | // } 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/log4j/SeaMonitorAppender.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.log4j; 2 | 3 | import com.github.seaframework.monitor.SeaMonitor; 4 | import com.github.seaframework.monitor.enums.CounterEnum; 5 | import org.apache.log4j.AppenderSkeleton; 6 | import org.apache.log4j.Level; 7 | import org.apache.log4j.spi.LoggingEvent; 8 | 9 | public class SeaMonitorAppender extends AppenderSkeleton { 10 | 11 | @Override 12 | protected void append(LoggingEvent event) { 13 | Level level = event.getLevel(); 14 | 15 | if (level.isGreaterOrEqual(Level.ERROR)) { 16 | logError(event); 17 | } 18 | } 19 | 20 | @Override 21 | public void close() { 22 | } 23 | 24 | private void logError(LoggingEvent event) { 25 | SeaMonitor.logCount(CounterEnum.SYS_LOG_COUNT.getKey()); 26 | } 27 | 28 | @Override 29 | public boolean requiresLayout() { 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/logback/SeaMonitorAppender.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.logback; 2 | 3 | import ch.qos.logback.classic.Level; 4 | import ch.qos.logback.classic.spi.ILoggingEvent; 5 | import ch.qos.logback.core.AppenderBase; 6 | import ch.qos.logback.core.LogbackException; 7 | import com.github.seaframework.monitor.SeaMonitor; 8 | import com.github.seaframework.monitor.enums.CounterEnum; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | /** 12 | * module name 13 | * 14 | * @author spy 15 | * @version 1.0 2020/5/3 16 | * @since 1.0 17 | */ 18 | @Slf4j 19 | public class SeaMonitorAppender extends AppenderBase { 20 | 21 | @Override 22 | protected void append(ILoggingEvent event) { 23 | try { 24 | Level level = event.getLevel(); 25 | 26 | if (level.isGreaterOrEqual(Level.ERROR)) { 27 | logError(event); 28 | } 29 | } catch (Exception ex) { 30 | throw new LogbackException(event.getFormattedMessage(), ex); 31 | } 32 | } 33 | 34 | private void logError(ILoggingEvent event) { 35 | SeaMonitor.logCount(CounterEnum.SYS_LOG_COUNT.getKey()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/message/MessageProducer.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.message; 2 | 3 | import com.github.seaframework.monitor.dto.MetricDTO; 4 | 5 | /** 6 | * module name 7 | * 8 | * @author spy 9 | * @version 1.0 2020/3/27 10 | * @since 1.0 11 | */ 12 | public interface MessageProducer { 13 | 14 | void init(); 15 | 16 | void push(MetricDTO dto); 17 | 18 | void shutdown(); 19 | } 20 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/message/disruptor/DefaultMessageProducer.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.message.disruptor; 2 | 3 | import com.github.seaframework.core.config.Configuration; 4 | import com.github.seaframework.core.config.ConfigurationFactory; 5 | import com.github.seaframework.monitor.common.MonitorConst; 6 | import com.github.seaframework.monitor.dto.MetricDTO; 7 | import com.github.seaframework.monitor.message.MessageProducer; 8 | import com.lmax.disruptor.ExceptionHandler; 9 | import com.lmax.disruptor.LiteTimeoutBlockingWaitStrategy; 10 | import com.lmax.disruptor.RingBuffer; 11 | import com.lmax.disruptor.WorkHandler; 12 | import com.lmax.disruptor.dsl.Disruptor; 13 | import com.lmax.disruptor.dsl.ProducerType; 14 | import lombok.extern.slf4j.Slf4j; 15 | 16 | import java.util.concurrent.ThreadFactory; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | /** 20 | * module name 21 | * 22 | * @author spy 23 | * @version 1.0 2020/3/27 24 | * @since 1.0 25 | */ 26 | @Slf4j 27 | public class DefaultMessageProducer implements MessageProducer { 28 | 29 | private volatile boolean init = false; 30 | private Disruptor disruptor; 31 | private RingBuffer ringBuffer; 32 | private int DEFAULT_BUFFER_SIZE = 4096; 33 | 34 | public void init() { 35 | if (init) { 36 | return; 37 | } 38 | // 39 | Configuration config = ConfigurationFactory.getInstance(); 40 | int consumerCount = config.getInt(MonitorConst.CONFIG_KEY_CONSUMER_COUNT, MonitorConst.DEFAULT_CONSUMER_COUNT); 41 | 42 | ThreadFactory threadFactory = r -> new Thread(r, "sea-monitor-disruptor"); 43 | 44 | MessageEventFactory factory = new MessageEventFactory(); 45 | int bufferSize = DEFAULT_BUFFER_SIZE; 46 | 47 | disruptor = new Disruptor<>(factory, bufferSize, threadFactory, ProducerType.MULTI, new LiteTimeoutBlockingWaitStrategy(500, TimeUnit.MILLISECONDS)); 48 | 49 | WorkHandler[] workHandlers = new WorkHandler[consumerCount]; 50 | for (int i = 0; i < consumerCount; i++) { 51 | workHandlers[i] = new MessageConsumerHandler(); 52 | } 53 | 54 | disruptor.handleEventsWithWorkerPool(workHandlers); 55 | 56 | disruptor.setDefaultExceptionHandler(new ExceptionHandler() { 57 | @Override 58 | public void handleEventException(Throwable ex, long sequence, MessageEvent event) { 59 | log.error("event exception =>,{},{},{}", ex, sequence, event); 60 | } 61 | 62 | @Override 63 | public void handleOnStartException(Throwable ex) { 64 | log.error("on start exception", ex); 65 | } 66 | 67 | @Override 68 | public void handleOnShutdownException(Throwable ex) { 69 | log.error("on shutdown exception", ex); 70 | } 71 | }); 72 | 73 | disruptor.start(); 74 | ringBuffer = disruptor.getRingBuffer(); 75 | init = true; 76 | } 77 | 78 | private void checkInit() { 79 | init(); 80 | } 81 | 82 | /** 83 | * 添加数据 84 | * 85 | * @param metricDTO 86 | */ 87 | public void push(MetricDTO metricDTO) { 88 | 89 | try { 90 | checkInit(); 91 | 92 | long sequence = ringBuffer.next(); 93 | try { 94 | MessageEvent event = ringBuffer.get(sequence); 95 | event.setMetricDTO(metricDTO); 96 | } finally { 97 | ringBuffer.publish(sequence); 98 | } 99 | } catch (Exception e) { 100 | log.error("fail to push metric", e); 101 | } 102 | } 103 | 104 | /** 105 | * 释放资源 106 | */ 107 | public void shutdown() { 108 | disruptor.shutdown(); 109 | init = false; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/message/disruptor/MessageConsumerHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.message.disruptor; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import com.github.seaframework.monitor.dto.MetricDTO; 5 | import com.github.seaframework.monitor.message.simple.SimpleConsumerTask; 6 | import com.google.common.collect.Queues; 7 | import com.lmax.disruptor.WorkHandler; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import java.util.concurrent.BlockingQueue; 11 | import java.util.concurrent.TimeUnit; 12 | import java.util.concurrent.atomic.AtomicLong; 13 | 14 | /** 15 | * module name 16 | * 17 | * @author spy 18 | * @version 1.0 2020/3/27 19 | * @since 1.0 20 | */ 21 | @Slf4j 22 | public class MessageConsumerHandler implements WorkHandler { 23 | 24 | private boolean init = false; 25 | private int DEFAULT_QUEUE_SIZE = 5000; 26 | private BlockingQueue queue; 27 | private static final AtomicLong count = new AtomicLong(0); 28 | 29 | 30 | @Override 31 | public void onEvent(MessageEvent event) throws Exception { 32 | 33 | if (!init) { 34 | initQueue(); 35 | } 36 | try { 37 | queue.add(event.getMetricDTO()); 38 | } catch (Exception e) { 39 | log.error("fail to add to queue.", e); 40 | } 41 | } 42 | 43 | 44 | private void initQueue() { 45 | if (queue == null) { 46 | queue = Queues.newArrayBlockingQueue(DEFAULT_QUEUE_SIZE); 47 | } 48 | try { 49 | TimeUnit.MILLISECONDS.sleep(RandomUtil.randomInt(100, 500)); 50 | } catch (Exception e) { 51 | log.error("--", e); 52 | } 53 | SimpleConsumerTask task = new SimpleConsumerTask(queue); 54 | Thread thread = new Thread(task); 55 | thread.setName("sea-monitor-message-consumer-" + count.incrementAndGet()); 56 | thread.start(); 57 | 58 | Thread shutdownThread = new Thread(() -> task.stop()); 59 | shutdownThread.setDaemon(true); 60 | Runtime.getRuntime().addShutdownHook(shutdownThread); 61 | 62 | init = true; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/message/disruptor/MessageEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.message.disruptor; 2 | 3 | import com.github.seaframework.monitor.dto.MetricDTO; 4 | import lombok.Data; 5 | 6 | /** 7 | * module name 8 | * 9 | * @author spy 10 | * @version 1.0 2020/3/27 11 | * @since 1.0 12 | */ 13 | 14 | @Data 15 | public class MessageEvent { 16 | 17 | private MetricDTO metricDTO; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/message/disruptor/MessageEventFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.message.disruptor; 2 | 3 | import com.lmax.disruptor.EventFactory; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | /** 7 | * 模块名 8 | * 9 | * @author shi.pengyan 10 | * @date 2019-03-27 9:37 11 | */ 12 | @Slf4j 13 | public class MessageEventFactory implements EventFactory { 14 | @Override 15 | public MessageEvent newInstance() { 16 | return new MessageEvent(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/message/simple/SimpleConsumerTask.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.message.simple; 2 | 3 | import com.github.seaframework.core.config.Configuration; 4 | import com.github.seaframework.core.config.ConfigurationFactory; 5 | import com.github.seaframework.core.http.simple.HttpClientUtil; 6 | import com.github.seaframework.core.model.BaseResult; 7 | import com.github.seaframework.core.util.JSONUtil; 8 | import com.github.seaframework.core.util.ListUtil; 9 | import com.github.seaframework.monitor.common.MonitorConst; 10 | import com.github.seaframework.monitor.dto.MetricDTO; 11 | import com.google.common.collect.Queues; 12 | import lombok.extern.slf4j.Slf4j; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.concurrent.BlockingQueue; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | /** 20 | * module name 21 | * 22 | * @author spy 23 | * @version 1.0 2020/3/27 24 | * @since 1.0 25 | */ 26 | @Slf4j 27 | public class SimpleConsumerTask implements Runnable { 28 | private volatile boolean isRunning = true; 29 | private BlockingQueue queue; 30 | 31 | 32 | public SimpleConsumerTask(BlockingQueue queue) { 33 | this.queue = queue; 34 | } 35 | 36 | /** 37 | * 消费者 38 | */ 39 | public void run() { 40 | Configuration config = ConfigurationFactory.getInstance(); 41 | int maxElementCount = config.getInt(MonitorConst.CONFIG_KEY_SEND_ELEMENT_MAX_COUNT, MonitorConst.DEFAULT_SEND_ELEMENT_MAX_COUNT); 42 | int timeout = config.getInt(MonitorConst.CONFIG_KEY_SEND_PERIOD_TIME, MonitorConst.DEFAULT_PUSH_PERIOD_TIME); 43 | 44 | while (isRunning) { 45 | try { 46 | List metricDTOList = new ArrayList<>(); 47 | // 满足200元素 或10s 即可提交 48 | Queues.drain(queue, metricDTOList, maxElementCount, timeout, TimeUnit.SECONDS); 49 | send(metricDTOList); 50 | Thread.sleep(200); 51 | } catch (Exception e) { 52 | log.error(" drain queues error:", e); 53 | } 54 | } 55 | } 56 | 57 | public void stop() { 58 | isRunning = false; 59 | } 60 | 61 | private void send(List metricDTOList) { 62 | if (ListUtil.isEmpty(metricDTOList)) { 63 | return; 64 | } 65 | String url = ConfigurationFactory.getInstance().getString(MonitorConst.CONFIG_KEY_URI, MonitorConst.DEFAULT_COLLECTOR_URI); 66 | BaseResult ret = HttpClientUtil.postJSONSafe(url, JSONUtil.toStr(metricDTOList)); 67 | log.info("post to sea monitor server [count={},success={}]", metricDTOList.size(), ret.getSuccess()); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/message/simple/SimpleMessageProducer.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.message.simple; 2 | 3 | import com.github.seaframework.monitor.dto.MetricDTO; 4 | import com.github.seaframework.monitor.message.MessageProducer; 5 | import com.google.common.collect.Queues; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.util.concurrent.BlockingQueue; 9 | 10 | /** 11 | * module name 12 | * 13 | * @author spy 14 | * @version 1.0 2020/3/27 15 | * @since 1.0 16 | */ 17 | @Slf4j 18 | public class SimpleMessageProducer implements MessageProducer { 19 | 20 | private BlockingQueue queue; 21 | private int DEFAULT_QUEUE_SIZE = 5000; 22 | 23 | @Override 24 | public void init() { 25 | 26 | queue = Queues.newArrayBlockingQueue(DEFAULT_QUEUE_SIZE); 27 | 28 | Thread consumeThread = new Thread(new SimpleConsumerTask(queue)); 29 | consumeThread.setName("sea-monitor-simple-message-consumer"); 30 | consumeThread.start(); 31 | 32 | } 33 | 34 | @Override 35 | public void push(MetricDTO dto) { 36 | try { 37 | if (queue.size() >= DEFAULT_QUEUE_SIZE) { 38 | log.warn("queue has reach to MAX SIZE[{}]", DEFAULT_QUEUE_SIZE); 39 | return; 40 | } 41 | queue.offer(dto); 42 | } catch (Exception e) { 43 | log.error("fail to push metric dto", e); 44 | } 45 | } 46 | 47 | @Override 48 | public void shutdown() { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/mybatis/MybatisMonitorInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.mybatis; 2 | 3 | import com.github.seaframework.monitor.SeaMonitor; 4 | import com.github.seaframework.monitor.common.MonitorConst; 5 | import com.github.seaframework.monitor.dto.MetricDTO; 6 | import com.github.seaframework.monitor.enums.CounterEnum; 7 | import com.github.seaframework.monitor.heartbeat.data.DataStats; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.ibatis.cache.CacheKey; 10 | import org.apache.ibatis.executor.Executor; 11 | import org.apache.ibatis.mapping.BoundSql; 12 | import org.apache.ibatis.mapping.MappedStatement; 13 | import org.apache.ibatis.plugin.*; 14 | import org.apache.ibatis.session.ResultHandler; 15 | import org.apache.ibatis.session.RowBounds; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.Properties; 20 | 21 | /** 22 | * module name 23 | * 24 | * @author spy 25 | * @version 1.0 2020/4/27 26 | * @since 1.0 27 | */ 28 | @Slf4j 29 | @Intercepts({ 30 | @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), 31 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), 32 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}) 33 | }) 34 | public class MybatisMonitorInterceptor implements Interceptor { 35 | 36 | private static final int MAX_RECORD_SIZE = 5000; 37 | //10s 38 | private static final int MIN_COST_TIME = 1000 * 5; 39 | 40 | @Override 41 | public Object intercept(Invocation invocation) throws Throwable { 42 | if (log.isDebugEnabled()) { 43 | log.debug("mybatis monitor interceptor begin."); 44 | } 45 | long start = System.currentTimeMillis(); 46 | Object returnValue; 47 | try { 48 | returnValue = invocation.proceed(); 49 | dealReturnValue(returnValue); 50 | } catch (Exception e) { 51 | if (SeaMonitor.isEnabled()) { 52 | log.error("DB500"); 53 | MetricDTO metricDTO = new MetricDTO(); 54 | metricDTO.setMetric(MonitorConst.METRIC_DB_SQL_ERROR); 55 | metricDTO.setValue(1); 56 | metricDTO.setErrorFlag(true); 57 | metricDTO.setTraceIdFlag(true); 58 | SeaMonitor.logMetric(metricDTO); 59 | 60 | // for sql total 61 | DataStats dataStats = DataStats.currentStatsHolder(); 62 | dataStats.logCount(CounterEnum.DB_SQL_ERROR_COUNT); 63 | } 64 | throw e; 65 | } finally { 66 | postCheck(start); 67 | } 68 | 69 | if (log.isDebugEnabled()) { 70 | log.debug("mybatis monitor interceptor end."); 71 | } 72 | 73 | return returnValue; 74 | } 75 | 76 | private void postCheck(long start) { 77 | if (!SeaMonitor.isEnabled()) { 78 | return; 79 | } 80 | long cost = System.currentTimeMillis() - start; 81 | if (cost > MIN_COST_TIME) { 82 | log.warn("DB502"); 83 | MetricDTO metricDTO = new MetricDTO(); 84 | metricDTO.setMetric(MonitorConst.METRIC_DB_SQL_COST); 85 | metricDTO.setValue(cost); 86 | metricDTO.setErrorFlag(true); 87 | metricDTO.setTraceIdFlag(true); 88 | SeaMonitor.logMetric(metricDTO); 89 | } 90 | } 91 | 92 | private void dealReturnValue(Object returnValue) { 93 | if (!SeaMonitor.isEnabled()) { 94 | return; 95 | } 96 | if (returnValue == null) { 97 | return; 98 | } 99 | 100 | if (returnValue instanceof ArrayList) { 101 | List data = (ArrayList) returnValue; 102 | if (data.size() >= MAX_RECORD_SIZE) { 103 | log.error("DB501"); 104 | MetricDTO metricDTO = new MetricDTO(); 105 | metricDTO.setMetric(MonitorConst.METRIC_DB_SQL_LARGE_RECORD_ERROR); 106 | metricDTO.setValue(1); 107 | metricDTO.setErrorFlag(true); 108 | metricDTO.setTraceIdFlag(true); 109 | SeaMonitor.logMetric(metricDTO); 110 | } 111 | } 112 | 113 | } 114 | 115 | @Override 116 | public Object plugin(Object target) { 117 | 118 | return Plugin.wrap(target, this); 119 | } 120 | 121 | @Override 122 | public void setProperties(Properties properties) { 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/samplers/PercentageBasedSampler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.github.seaframework.monitor.samplers; 18 | 19 | import java.util.BitSet; 20 | import java.util.Random; 21 | import java.util.concurrent.atomic.AtomicLong; 22 | 23 | /** 24 | * SofaTracerPercentageBasedSampler 25 | * 26 | * @author yangguanchao 27 | * @since 2017/06/19 28 | */ 29 | public class PercentageBasedSampler implements Sampler { 30 | 31 | public static final String TYPE = "PercentageBasedSampler"; 32 | 33 | private final AtomicLong counter = new AtomicLong(0); 34 | private final BitSet sampleDecisions; 35 | private final SamplerProperties configuration; 36 | 37 | public PercentageBasedSampler(SamplerProperties configuration) { 38 | int outOf100 = (int) (configuration.getPercentage()); 39 | this.sampleDecisions = randomBitSet(100, outOf100, new Random()); 40 | this.configuration = configuration; 41 | } 42 | 43 | @Override 44 | public SamplingStatus sample() { 45 | SamplingStatus samplingStatus = new SamplingStatus(); 46 | 47 | if (this.configuration.getPercentage() == 0) { 48 | samplingStatus.setSampled(false); 49 | return samplingStatus; 50 | } else if (this.configuration.getPercentage() == 100) { 51 | samplingStatus.setSampled(true); 52 | return samplingStatus; 53 | } 54 | boolean result = this.sampleDecisions.get((int) (this.counter.getAndIncrement() % 100)); 55 | samplingStatus.setSampled(result); 56 | return samplingStatus; 57 | } 58 | 59 | @Override 60 | public String getType() { 61 | return TYPE; 62 | } 63 | 64 | @Override 65 | public void close() { 66 | //do nothing 67 | } 68 | 69 | /** 70 | * Reservoir sampling algorithm borrowed from Stack Overflow. 71 | *

72 | * http://stackoverflow.com/questions/12817946/generate-a-random-bitset-with-n-1s 73 | * 74 | * @param size 大小 75 | * @param cardinality 基数 76 | * @param rnd 随机种子 77 | * @return BitSet 78 | */ 79 | public static BitSet randomBitSet(int size, int cardinality, Random rnd) { 80 | BitSet result = new BitSet(size); 81 | int[] chosen = new int[cardinality]; 82 | int i; 83 | for (i = 0; i < cardinality; ++i) { 84 | chosen[i] = i; 85 | result.set(i); 86 | } 87 | for (; i < size; ++i) { 88 | int j = rnd.nextInt(i + 1); 89 | if (j < cardinality) { 90 | result.clear(chosen[j]); 91 | result.set(i); 92 | chosen[j] = i; 93 | } 94 | } 95 | return result; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/samplers/Sampler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.github.seaframework.monitor.samplers; 18 | 19 | 20 | public interface Sampler { 21 | 22 | SamplingStatus sample(); 23 | 24 | String getType(); 25 | 26 | /** 27 | * Release any resources used by the sampler. 28 | */ 29 | void close(); 30 | } 31 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/samplers/SamplerProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.github.seaframework.monitor.samplers; 18 | 19 | /** 20 | * SamplerProperties 21 | * 22 | * @author yangguanchao 23 | * @since 2017/06/20 24 | */ 25 | public class SamplerProperties { 26 | /** 27 | * Percentage of requests that should be sampled. E.g. 1.0 - 100% requests should be 28 | * sampled. The precision is whole-numbers only (i.e. there's no support for 1.0 of 29 | * the traces). 30 | */ 31 | private float percentage = 100; 32 | 33 | /** 34 | * if use custom rule, you can implements Sample interface and provide this class name 35 | */ 36 | private String ruleClassName; 37 | 38 | public float getPercentage() { 39 | return percentage; 40 | } 41 | 42 | public void setPercentage(float percentage) { 43 | this.percentage = percentage; 44 | } 45 | 46 | public String getRuleClassName() { 47 | return ruleClassName; 48 | } 49 | 50 | public void setRuleClassName(String ruleClassName) { 51 | this.ruleClassName = ruleClassName; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/samplers/SamplingStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.github.seaframework.monitor.samplers; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | public class SamplingStatus { 23 | 24 | private boolean isSampled = false; 25 | 26 | /*** 27 | * 允许在 RootSpan 处放置 tags 28 | */ 29 | private Map tags = new HashMap(); 30 | 31 | public boolean isSampled() { 32 | return isSampled; 33 | } 34 | 35 | public void setSampled(boolean sampled) { 36 | isSampled = sampled; 37 | } 38 | 39 | public Map getTags() { 40 | return tags; 41 | } 42 | 43 | public void setTags(Map tags) { 44 | this.tags = tags; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/trace/TraceExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.trace; 2 | 3 | /** 4 | * module name 5 | * 6 | * @author spy 7 | * @version 1.0 2020/5/9 8 | * @since 1.0 9 | */ 10 | public interface TraceExtension { 11 | /** 12 | * 返回tranceId 13 | * 14 | * @return 15 | */ 16 | String getTraceId(); 17 | } 18 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/trace/impl/DefaultTraceExtension.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.trace.impl; 2 | 3 | import com.alipay.common.tracer.core.context.span.SofaTracerSpanContext; 4 | import com.alipay.common.tracer.core.holder.SofaTraceContextHolder; 5 | import com.github.seaframework.core.loader.LoadLevel; 6 | import com.github.seaframework.monitor.trace.TraceExtension; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | /** 10 | * module name 11 | * 12 | * @author spy 13 | * @version 1.0 2020/5/9 14 | * @since 1.0 15 | */ 16 | @Slf4j 17 | @LoadLevel(name = "default") 18 | public class DefaultTraceExtension implements TraceExtension { 19 | 20 | @Override 21 | public String getTraceId() { 22 | try { 23 | SofaTracerSpanContext spanContext = SofaTraceContextHolder.getSofaTraceContext() 24 | .getCurrentSpan() 25 | .getSofaTracerSpanContext(); 26 | return spanContext.getTraceId(); 27 | } catch (Exception e) { 28 | log.error("fail to get span_id"); 29 | } 30 | 31 | return ""; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/util/JMXUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.util; 2 | 3 | import javax.management.*; 4 | import java.lang.management.ManagementFactory; 5 | import java.util.Set; 6 | 7 | public class JMXUtil { 8 | 9 | /** 10 | * 注册一个MBean 11 | */ 12 | public static ObjectName register(String name, Object mbean) { 13 | try { 14 | ObjectName objectName = new ObjectName(name); 15 | MBeanServer mbeanServer = getMBeanServer(); 16 | try { 17 | mbeanServer.registerMBean(mbean, objectName); 18 | } catch (InstanceAlreadyExistsException ex) { 19 | mbeanServer.unregisterMBean(objectName); 20 | mbeanServer.registerMBean(mbean, objectName); 21 | } 22 | return objectName; 23 | } catch (JMException e) { 24 | throw new IllegalArgumentException(name, e); 25 | } 26 | } 27 | 28 | /** 29 | * 取消一个MBean 30 | */ 31 | public static void unregister(String name) { 32 | try { 33 | MBeanServer mbeanServer = getMBeanServer(); 34 | mbeanServer.unregisterMBean(new ObjectName(name)); 35 | } catch (JMException e) { 36 | throw new IllegalArgumentException(name, e); 37 | } 38 | } 39 | 40 | /** 41 | * 生成一个ObjectName,如果出错,返回null 42 | */ 43 | public static ObjectName createObjectName(String pattern) { 44 | try { 45 | return new ObjectName(pattern); 46 | } catch (Exception ex) { 47 | // Ignore. 48 | } 49 | 50 | return null; 51 | } 52 | 53 | /** 54 | * 获取类型Pattern列表 55 | */ 56 | public static ObjectName[] getObjectNames(ObjectName pattern) { 57 | ObjectName[] result = new ObjectName[0]; 58 | Set objectNames = getMBeanServer().queryNames(pattern, null); 59 | if (objectNames != null && !objectNames.isEmpty()) { 60 | result = objectNames.toArray(new ObjectName[objectNames.size()]); 61 | } 62 | return result; 63 | } 64 | 65 | public static MBeanServer getMBeanServer() { 66 | MBeanServer mBeanServer = null; 67 | if (MBeanServerFactory.findMBeanServer(null).size() > 0) { 68 | mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0); 69 | } else { 70 | mBeanServer = ManagementFactory.getPlatformMBeanServer(); 71 | } 72 | return mBeanServer; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/util/MonitorPushScheduler.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.ScheduledExecutorService; 9 | import java.util.concurrent.ThreadFactory; 10 | 11 | /** 12 | * module name 13 | * 14 | * @author spy 15 | * @version 1.0 2020/3/27 16 | * @since 1.0 17 | */ 18 | @Slf4j 19 | public class MonitorPushScheduler { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(MonitorPushScheduler.class); 22 | 23 | private static final ScheduledExecutorService MonitorScheduler = Executors.newSingleThreadScheduledExecutor( 24 | new ThreadFactory() { 25 | @Override 26 | public Thread newThread(Runnable r) { 27 | return new Thread(r, "sea-monitor-push-scheduler"); 28 | } 29 | 30 | }); 31 | 32 | 33 | public static void init() { 34 | logger.info("MonitorPushScheduler start"); 35 | // MonitorScheduler.scheduleAtFixedRate(new MonitorPushRunner(), MonitorConst.PUSH_PERIOD_TIME, 36 | // MonitorConst.PUSH_PERIOD_TIME, TimeUnit.SECONDS); 37 | } 38 | 39 | // static class MonitorPushRunner implements Runnable { 40 | // 41 | // @Override 42 | // public void run() { 43 | // try { 44 | // Map monitors = Maps.newHashMap(); 45 | // FalconMonitor.generateBusinessMetrics(monitors); 46 | // MonitorSendUtil.send(monitors); 47 | // } catch (Exception e) { 48 | // logger.error("run MonitorPushRunner exception", e); 49 | // } 50 | // } 51 | // } 52 | 53 | public static void destroy() { 54 | MonitorScheduler.shutdownNow(); 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/util/MonitorSendUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.util; 2 | 3 | import com.github.seaframework.core.http.simple.HttpClientUtil; 4 | import com.github.seaframework.core.model.BaseResult; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * module name 9 | * 10 | * @author spy 11 | * @version 1.0 2020/3/27 12 | * @since 1.0 13 | */ 14 | @Slf4j 15 | public class MonitorSendUtil { 16 | public void send(String url, Object obj) { 17 | BaseResult ret = HttpClientUtil.postJSONSafe(url, obj); 18 | if (!ret.getSuccess()) { 19 | log.warn("sea monitor send error."); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/util/TagUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * module name 7 | * 8 | * @author spy 9 | * @version 1.0 2020/3/24 10 | * @since 1.0 11 | */ 12 | @Slf4j 13 | public class TagUtil { 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/util/ThreadPoolUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.util; 2 | 3 | import com.github.seaframework.core.util.NumberUtil; 4 | import com.github.seaframework.monitor.vo.ThreadPoolStatus; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.math.RoundingMode; 8 | import java.util.concurrent.ThreadPoolExecutor; 9 | 10 | /** 11 | * module name 12 | * 13 | * @author spy 14 | * @version 1.0 2020/4/9 15 | * @since 1.0 16 | */ 17 | @Slf4j 18 | public class ThreadPoolUtil { 19 | 20 | 21 | /** 22 | * get thread pool status 23 | * 24 | * @param tpe 25 | * @return 26 | */ 27 | public static ThreadPoolStatus getStatus(ThreadPoolExecutor tpe) { 28 | ThreadPoolStatus status = new ThreadPoolStatus(); 29 | if (tpe == null) { 30 | return status; 31 | } 32 | 33 | status.setMax(tpe.getMaximumPoolSize()); 34 | status.setCore(tpe.getCorePoolSize()); 35 | status.setLargest(tpe.getLargestPoolSize()); 36 | status.setActive(tpe.getActiveCount()); 37 | status.setTask(tpe.getTaskCount()); 38 | status.setActivePercent(NumberUtil.divide(status.getActive(), status.getMax(), 3, RoundingMode.UP).doubleValue()); 39 | return status; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/util/TraceUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * module name 7 | * 8 | * @author spy 9 | * @version 1.0 2020/5/8 10 | * @since 1.0 11 | */ 12 | @Slf4j 13 | public class TraceUtil { 14 | 15 | public static String getTraceId() { 16 | //TODO 17 | return ""; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sea-monitor/src/main/java/com/github/seaframework/monitor/vo/ThreadPoolStatus.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * module name 10 | * 11 | * @author spy 12 | * @version 1.0 2020/4/9 13 | * @since 1.0 14 | */ 15 | 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @EqualsAndHashCode 20 | public class ThreadPoolStatus { 21 | 22 | private String poolName; 23 | 24 | private int max; 25 | private int core; 26 | private int largest; 27 | private int active; 28 | private long task; 29 | private double activePercent; 30 | 31 | // unused 32 | private int queueSize; 33 | } 34 | -------------------------------------------------------------------------------- /sea-monitor/src/main/resources/META-INF/services/com.github.seaframework.monitor.trace.TraceExtension: -------------------------------------------------------------------------------- 1 | com.github.seaframework.monitor.trace.impl.DefaultTraceExtension -------------------------------------------------------------------------------- /sea-monitor/src/main/resources/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seaframework/sea-monitor-all/0dcd0c06fc16f88020db8d7e3bfb38c405dd6945/sea-monitor/src/main/resources/README.md -------------------------------------------------------------------------------- /sea-monitor/src/test/java/com/github/spy/sea/monitor/SeaMonitorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.seaframework.monitor; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.github.seaframework.monitor.dto.MetricDTO; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * module name 16 | * 17 | * @author spy 18 | * @version 1.0 2020/3/24 19 | * @since 1.0 20 | */ 21 | @Slf4j 22 | public class SeaMonitorTest { 23 | 24 | @Before 25 | public void before() throws Exception { 26 | SeaMonitor.enable(); 27 | } 28 | 29 | @Test 30 | public void run16() throws Exception { 31 | 32 | // Tags tags = Tags.of(TagConst.INSTANCE, "11"); 33 | // 34 | // tags.and(TagConst.INSTANCE, "11"); 35 | // 36 | // 37 | // System.out.println(tags); 38 | } 39 | 40 | 41 | @Test 42 | public void run31() throws Exception { 43 | SeaMonitor.enable(); 44 | 45 | SeaMonitor.logMetric("abc", 1); 46 | } 47 | 48 | @After 49 | public void after() throws Exception { 50 | TimeUnit.MINUTES.sleep(5); 51 | } 52 | 53 | 54 | @Test 55 | public void run51() throws Exception { 56 | MetricDTO dto = new MetricDTO(); 57 | 58 | dto.setErrorFlag(false); 59 | dto.setMetric("metric.11"); 60 | dto.setValue(1); 61 | 62 | Map extraMap = new HashMap<>(); 63 | extraMap.put("key", "value"); 64 | dto.setExtraMap(extraMap); 65 | 66 | System.out.println(JSON.toJSONString(dto)); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /sea-monitor/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | %d{HH:mm:ss.SSS} %level [%thread] [%class{36}.%M:%line] - %m %n 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /sea-monitor/src/test/resources/sea.monitor.properties: -------------------------------------------------------------------------------- 1 | # 2 | # current region 3 | sea.region=xinxiang 4 | # sea monitor 5 | sea.monitor.enabled=true 6 | # application name 7 | sea.monitor.endpoint=vs 8 | # sea monitor uri 9 | sea.monitor.uri=http://127.0.0.1:1988/v1/push 10 | # log mode 11 | # 0 report to remote server (by default) 12 | # 1 log to local log file 13 | sea.monitor.mode=0 14 | # trace_id default generate by sofa tracer. 15 | sea.monitor.trace=default 16 | # \u91C7\u6837\u7387 17 | sea.monitor.sample.percent=100 18 | # \u6D88\u8D39\u8005\u4E2A\u6570 19 | sea.monitor.consumer.count=1 20 | # \u53D1\u9001\u7684\u6700\u5927\u5143\u7D20\u4E2A\u6570 21 | sea.monitor.send.element.max.count=200 22 | # \u53D1\u9001\u95F4\u9694 23 | sea.monitor.send.period.time=20 --------------------------------------------------------------------------------