├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── LICENSE ├── README.md ├── build.sh ├── cicada-client ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── yirendai │ │ │ └── infra │ │ │ └── cicada │ │ │ ├── capture │ │ │ ├── CicadaDubboFilter.java │ │ │ ├── CustomSampler.java │ │ │ ├── HttpClientAop.java │ │ │ ├── HttpFilter.java │ │ │ ├── MybatisInterceptor.java │ │ │ ├── Sampler.java │ │ │ ├── Traceable.java │ │ │ ├── TraceableAop.java │ │ │ ├── Tracer.java │ │ │ └── TracerUtils.java │ │ │ ├── config │ │ │ └── CicadaConfig.java │ │ │ ├── transfer │ │ │ ├── DeliverService.java │ │ │ ├── Transfer.java │ │ │ ├── TransferEngine.java │ │ │ ├── disruptor │ │ │ │ ├── DisruptorTransfer.java │ │ │ │ ├── SpanEvent.java │ │ │ │ ├── SpanEventFactory.java │ │ │ │ ├── SpanEventHandler.java │ │ │ │ └── SpanEventProducer.java │ │ │ └── impl │ │ │ │ └── HttpPostDeliverService.java │ │ │ └── utils │ │ │ └── SpringContextUtil.java │ └── resources │ │ └── META-INF │ │ └── dubbo │ │ └── com.alibaba.dubbo.rpc.Filter │ └── test │ ├── java │ ├── com │ │ └── yirendai │ │ │ └── infra │ │ │ └── cicada │ │ │ ├── BenchmarkTransfer.java │ │ │ ├── ExceptionTest.java │ │ │ └── HttpPostDeliverServiceTest.java │ └── demo │ │ ├── consumer │ │ └── DemoConsumer.java │ │ ├── provider │ │ ├── DemoProvider.java │ │ ├── DemoService.java │ │ └── DemoServiceImpl.java │ │ └── provider2 │ │ ├── DemoProvider2.java │ │ ├── DemoService2.java │ │ └── DemoServiceImpl2.java │ └── resources │ ├── cicada-config.xml │ ├── dubbo-demo-consumer.xml │ ├── dubbo-demo-provider.xml │ ├── dubbo-demo-provider2.xml │ ├── dubbo.properties │ └── logback.xml ├── cicada-collector ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── yirendai │ │ │ └── infra │ │ │ └── cicada │ │ │ ├── Application.java │ │ │ ├── ApplicationShutdown.java │ │ │ ├── config │ │ │ └── CicadaCollectorProps.java │ │ │ ├── repository │ │ │ ├── LogReader.java │ │ │ └── TraceElasticRepository.java │ │ │ ├── service │ │ │ ├── ElasticUploadService.java │ │ │ └── LogCollectService.java │ │ │ └── util │ │ │ ├── BufferedFile.java │ │ │ ├── ServiceRegisterManager.java │ │ │ ├── TraceChainModelGenerator.java │ │ │ ├── elastic │ │ │ ├── DayRotatedIndexManager.java │ │ │ ├── IndexConfigLoader.java │ │ │ └── IndexManager.java │ │ │ └── progress │ │ │ ├── FileProgressRecorder.java │ │ │ ├── MessageWasher.java │ │ │ ├── Progress.java │ │ │ └── ProgressRecorder.java │ └── resources │ │ ├── application.yml │ │ ├── elastic │ │ ├── annotation.settings │ │ ├── span.settings │ │ └── trace.settings │ │ ├── logback-spring.xml │ │ └── spy.properties │ └── test │ ├── java │ └── com │ │ └── yirendai │ │ └── infra │ │ └── cicada │ │ └── CollectorTest.java │ └── resources │ └── logback-test.xml ├── cicada-common-trace ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── yirendai │ │ └── infra │ │ └── cicada │ │ ├── constants │ │ ├── AnnotationType.java │ │ └── BinaryAnnotationType.java │ │ ├── entity │ │ └── trace │ │ │ ├── Annotation.java │ │ │ ├── BinaryAnnotation.java │ │ │ ├── Endpoint.java │ │ │ └── Span.java │ │ └── utils │ │ └── IpUtils.java │ └── test │ └── java │ └── com │ └── yirendai │ └── infra │ └── cicada │ └── SpanTest.java ├── cicada-common ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── yirendai │ └── infra │ └── cicada │ ├── configure │ └── ElasticSearchConfigure.java │ ├── constants │ └── DateTimeFormats.java │ ├── entity │ ├── AppInfo.java │ ├── CollectEntity.java │ ├── MethodInfo.java │ ├── ServiceInfo.java │ ├── SpanEntity.java │ └── model │ │ ├── AnnotationModel.java │ │ └── SpanModel.java │ ├── repository │ ├── AppRepository.java │ ├── MethodRepository.java │ └── ServiceRepository.java │ ├── resource │ └── RegisterInfoResource.java │ ├── service │ ├── AppService.java │ ├── MethodService.java │ └── ServiceService.java │ └── utils │ └── TraceUtil.java ├── cicada-demo ├── cicada-demo-consumer-web │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── yirendai │ │ │ │ └── infra │ │ │ │ └── cicada │ │ │ │ └── demo │ │ │ │ └── consumer │ │ │ │ └── web │ │ │ │ ├── ConsumerController.java │ │ │ │ └── configuration │ │ │ │ └── DubboConfiguration.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── yirendai │ │ └── infra │ │ └── cicada │ │ └── demo │ │ └── consumer │ │ └── web │ │ └── AppTest.java ├── cicada-demo-provider-api │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── yirendai │ │ │ └── infra │ │ │ └── cicada │ │ │ └── demo │ │ │ └── provider │ │ │ └── api │ │ │ └── DemoService.java │ │ └── test │ │ └── java │ │ └── com │ │ └── yirendai │ │ └── infra │ │ └── cicada │ │ └── demo │ │ └── provider │ │ └── api │ │ └── AppTest.java ├── cicada-demo-provider │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── yirendai │ │ │ │ └── infra │ │ │ │ └── cicada │ │ │ │ └── demo │ │ │ │ └── provider │ │ │ │ ├── Provider.java │ │ │ │ ├── configuration │ │ │ │ └── DubboConfiguration.java │ │ │ │ └── service │ │ │ │ ├── DemoServiceImpl.java │ │ │ │ └── User.java │ │ └── resources │ │ │ ├── application.yml │ │ │ └── logback.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── yirendai │ │ └── infra │ │ └── cicada │ │ └── demo │ │ └── provider │ │ └── AppTest.java └── pom.xml ├── cicada-docs ├── cicada-client-performance.md ├── cicada-client-quick-start.md ├── cicada_demo_guide.md ├── cicada_deployment.md ├── cicada_design.md ├── cicada_statistic_design.md └── static │ └── images │ ├── a_distribution_trace.jpg │ ├── cat_architecture.jpg │ ├── cicada_architecture.jpg │ ├── cicada_dashboard_app.jpg │ ├── cicada_dashboard_method.jpg │ ├── cicada_dashboard_report.jpg │ ├── cicada_dashboard_service.jpg │ ├── cicada_dashboard_trace.jpg │ ├── cicada_deployment.jpg │ ├── cicada_deployment_nginx_ha.jpg │ ├── cicada_statistic_architecture.jpg │ ├── cicada_statistic_init.jpg │ ├── cicada_statistic_process.jpg │ ├── cicada_web_swagger.jpg │ ├── distribution_trace_model.jpg │ ├── eagle_eye_architecture.jpg │ ├── hydra_architecture.jpg │ └── zipkin_architecture.jpg ├── cicada-nginx ├── cronolog-1.6.2.tar.gz ├── deploy.sh └── nginx.tar.gz ├── cicada-web ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── yirendai │ │ │ └── infra │ │ │ └── cicada │ │ │ ├── Application.java │ │ │ ├── ApplicationStartup.java │ │ │ ├── api │ │ │ └── rest │ │ │ │ ├── EntityApi.java │ │ │ │ ├── ProjectInfoServiceApi.java │ │ │ │ └── StatisInfoApi.java │ │ │ ├── cluster │ │ │ ├── ClusterJobMonitor.java │ │ │ ├── ClusterLeaderManager.java │ │ │ ├── ClusterNodeRegister.java │ │ │ ├── JobDispatcher.java │ │ │ └── JobProcessor.java │ │ │ ├── configure │ │ │ ├── CicadaWebProps.java │ │ │ ├── CuratorZookeeperConfigure.java │ │ │ ├── JobCacheConfigure.java │ │ │ └── SwaggerConfig.java │ │ │ ├── constants │ │ │ ├── ApiDocs.java │ │ │ └── AppError.java │ │ │ ├── entity │ │ │ ├── Fragment.java │ │ │ ├── Job.java │ │ │ ├── JobEntity.java │ │ │ ├── JobSlice.java │ │ │ ├── SpanStatisInfo.java │ │ │ └── StatisInfo.java │ │ │ ├── exception │ │ │ ├── AppResponseEntityExceptionHandler.java │ │ │ ├── BadRequestException.java │ │ │ ├── ErrorMessage.java │ │ │ ├── InternalServerErrorException.java │ │ │ └── NotFoundException.java │ │ │ ├── repository │ │ │ ├── AnnotationRepository.java │ │ │ ├── AppManagerRepository.java │ │ │ ├── SpanRepository.java │ │ │ ├── SpanStatisInfoRepository.java │ │ │ └── StatisInfoBulkRepository.java │ │ │ ├── request │ │ │ ├── EntityPageRequest.java │ │ │ ├── StatisInfoPageRequest.java │ │ │ └── StatisInfoRequest.java │ │ │ ├── service │ │ │ ├── AppManagerService.java │ │ │ ├── SpanService.java │ │ │ ├── SpanStatisInfoService.java │ │ │ ├── StatisticService.java │ │ │ └── TraceService.java │ │ │ ├── task │ │ │ ├── ExpiresCleanTask.java │ │ │ └── LogStatistician.java │ │ │ └── util │ │ │ ├── ElasticIndexManager.java │ │ │ ├── Messages.java │ │ │ └── ZookeeperUtil.java │ └── resources │ │ ├── application.yml │ │ ├── logback-spring.xml │ │ ├── spy.properties │ │ └── sql │ │ └── init.sql │ └── test │ └── resources │ ├── logback-test.xml │ └── spy.properties ├── pom.xml └── scripts ├── collector_run.sh ├── init.sql └── web_run.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # maven ignore 2 | 3 | *.eclipse-pmd 4 | *target/ 5 | !tools/*.jar 6 | *.war 7 | *.zip 8 | *.tar 9 | # *.tar.gz 10 | bin/ 11 | build/ 12 | ajcore.* 13 | 14 | # eclipse ignore 15 | *.settings/ 16 | *.project 17 | *.classpath 18 | 19 | # idea ignore 20 | .idea/ 21 | *.ipr 22 | *.iml 23 | *.iws 24 | 25 | # temp ignore 26 | *.log 27 | *.cache 28 | *.diff 29 | *.patch 30 | *.tmp 31 | 32 | # system ignore 33 | .DS_Store 34 | Thumbs.db 35 | 36 | sublime-project 37 | sublime-project.sublime-workspace 38 | 39 | coverage-report/ 40 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | commit build: 2 | script: 3 | - echo "test" # do nothing temporary 4 | 5 | public_test_env: 6 | stage: deploy 7 | script: 8 | - bash build.sh build_local 9 | only: 10 | - master 11 | 12 | Staging: 13 | stage: deploy 14 | script: 15 | - bash build.sh build_local 16 | only: 17 | - /^release.+$/ 18 | 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: java 4 | 5 | jdk: 6 | - oraclejdk8 7 | - oraclejdk7 8 | 9 | script: mvn clean package -Dmaven.test.skip=true 10 | 11 | cache: 12 | directories: 13 | - $HOME/.m2 14 | 15 | branches: 16 | only: 17 | - master 18 | - /^release-*$/ 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the “Software”), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 宜人贷分布式跟踪系统,基于[Google Dapper论文](http://bigbully.github.io/Dapper-translation/)实现。 3 | 4 | 项目名称“蝉”,取自《名贤集·七言集》“金风未动蝉先觉”,代表我们开发这个系统的初衷和思路,我们希望这套系统能够厘清复杂的业务系统中的调用关系,实现调用路径分析和调用链跟踪,对于业务系统中的性能瓶颈以及异常信息能够做到“先知先觉”,帮助开发人员更快的排查问题。 5 | 6 | ## Cicada运行效果 7 | cicada的核心是调用链,通常来说,一个调用链是指一次业务请求涉及到的所有调用(包括方法调用、Http、SQL、IO...)。每次请求生成一个全局唯一的ID,通过这个ID将在分布在不同系统孤立的埋点数据串联起来,组合成调用链。 8 | 9 | cicada的埋点坐标,为App、Service、Method。App代表当前埋点所在的业务系统名称,通常代表一个RPC服务;Service是埋点所在的接口名;Method为埋点的方法。 10 | 11 | cicada的运行效果截图如下: 12 | + App列表视图 13 | ![cicada-dashboard-app.jpg](cicada-docs/static/images/cicada_dashboard_app.jpg) 14 | 15 | + App下的Service列表视图 16 | ![cicada-dashboard-service.jpg](cicada-docs/static/images/cicada_dashboard_service.jpg) 17 | 18 | + service下的Method列表视图 19 | ![cicada-dashboard-method.jpg](cicada-docs/static/images/cicada_dashboard_method.jpg) 20 | 21 | + 统计折线图 22 | 统计项目包括失败率、平均响应时间、最大相应时间、95line、999line等。下图显示平均相应时间的统计折线图。 23 | ![cicada-dashboard-report.jpg](cicada-docs/static/images/cicada_dashboard_report.jpg) 24 | 25 | + trace调用链视图 26 | 针对每个事件,标注事件属于正常(EVENT)还是异常(EXCEPTION)。同时以柱状的形式展现每一个事件的耗时。 27 | ![cicada-dashboard-trace.jpg](cicada-docs/static/images/cicada_dashboard_trace.jpg) 28 | 每行从左到右分别显示:当前调用链事件描述、事件类型、事件耗时(单位ms)。 29 | 事件描述信息较长,一行无法显示,通过鼠标单击可以查看完整的提示信息(图中红色椭圆区域标识)。 30 | 31 | # 帮助文档 32 | 1. [Cicada客户端使用](cicada-docs/cicada-client-quick-start.md) 33 | 2. [Cicada客户端压测说明](cicada-docs/cicada-client-performance.md) 34 | 3. [Cicada Demo使用说明](cicada-docs/cicada_demo_guide.md) 35 | 4. [Cicada总体设计文档](cicada-docs/cicada_design.md) 36 | 5. [Cicada统计模块设计文档](cicada-docs/cicada_statistic_design.md) 37 | 6. [Cicada部署文档](cicada-docs/cicada_deployment.md) 38 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## variables 4 | CICADA_COLLECTOR=cicada-collector 5 | CICADA_WEB=cicada-web 6 | SCRIPTS_DIR=./scripts 7 | 8 | function local_build() { 9 | ## package 10 | mvn clean package -Dmaven.test.skip=true 11 | 12 | BUILD_OUTPUT=./build 13 | 14 | # cicada-collector 15 | if [ ! -d $BUILD_OUTPUT/$CICADA_COLLECTOR ] 16 | then 17 | mkdir -p $BUILD_OUTPUT/$CICADA_COLLECTOR 18 | fi 19 | cp $CICADA_COLLECTOR/target/cicada-collector*.jar $BUILD_OUTPUT/$CICADA_COLLECTOR 20 | cp $CICADA_COLLECTOR/target/application.yml $BUILD_OUTPUT/$CICADA_COLLECTOR 21 | cp $CICADA_COLLECTOR/target/logback-spring.xml $BUILD_OUTPUT/$CICADA_COLLECTOR 22 | cp $SCRIPTS_DIR/collector_run.sh $BUILD_OUTPUT/$CICADA_COLLECTOR/run.sh 23 | 24 | #cicada-web 25 | if [ ! -d $BUILD_OUTPUT/$CICADA_WEB ] 26 | then 27 | mkdir -p $BUILD_OUTPUT/$CICADA_WEB 28 | fi 29 | cp $CICADA_WEB/target/cicada-web-*.jar $BUILD_OUTPUT/$CICADA_WEB 30 | cp $CICADA_WEB/target/application.yml $BUILD_OUTPUT/$CICADA_WEB 31 | cp $CICADA_WEB/target/logback-spring.xml $BUILD_OUTPUT/$CICADA_WEB 32 | cp $SCRIPTS_DIR/web_run.sh $BUILD_OUTPUT/$CICADA_WEB/run.sh 33 | } 34 | 35 | case $1 in 36 | "local_build") 37 | local_build 38 | ;; 39 | 40 | *) 41 | echo -e "Usage: $0 { local_build }" 42 | ;; 43 | 44 | esac 45 | 46 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/capture/CustomSampler.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.capture; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.Random; 6 | 7 | /** 8 | * 用户自定义采样率实现。 用户在配置文件中指定采样率. 9 | * 10 | * @author Zecheng 11 | */ 12 | @Component 13 | public class CustomSampler implements Sampler { 14 | private static final int BASE = 100; 15 | 16 | private int sampleRate = 100; 17 | 18 | private final Random randIntGen = new Random(); 19 | 20 | public boolean isSample() { 21 | boolean result = false; 22 | if (sampleRate > 0) { 23 | final int randomValue = randIntGen.nextInt(BASE); 24 | if (randomValue < sampleRate) { 25 | result = true; 26 | } 27 | } 28 | 29 | return result; 30 | } 31 | 32 | public void setSampleRate(final int rate) { 33 | if (rate < 0) { 34 | this.sampleRate = 0; 35 | } else if (rate > BASE) { 36 | this.sampleRate = BASE; 37 | } else { 38 | this.sampleRate = rate; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/capture/HttpClientAop.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.capture; 2 | 3 | import org.apache.http.client.methods.HttpUriRequest; 4 | import org.aspectj.lang.ProceedingJoinPoint; 5 | import org.aspectj.lang.annotation.Around; 6 | import org.aspectj.lang.annotation.Aspect; 7 | 8 | @Aspect 9 | public class HttpClientAop { 10 | 11 | /** 12 | * 拦截HttpClient的Post与Get方法. 13 | * 14 | */ 15 | @Around("execution(* org.apache.http.client.HttpClient.execute(..)) && args(httpUriRequest)") 16 | public Object around(final ProceedingJoinPoint proceedingJoinPoint, final HttpUriRequest httpUriRequest) 17 | throws java.lang.Throwable { 18 | final long startTime = System.currentTimeMillis(); 19 | final Object[] args = proceedingJoinPoint.getArgs(); 20 | final Object result = proceedingJoinPoint.proceed(args); 21 | 22 | if (httpUriRequest instanceof HttpUriRequest) { 23 | final String methodName = httpUriRequest.getMethod(); 24 | final String className = httpUriRequest.getURI().toString(); 25 | 26 | Tracer.getInstance().addBinaryAnnotation(className, methodName, (int) (System.currentTimeMillis() - startTime)); 27 | } 28 | 29 | return result; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/capture/MybatisInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.capture; 2 | 3 | import org.apache.ibatis.executor.Executor; 4 | import org.apache.ibatis.mapping.MappedStatement; 5 | import org.apache.ibatis.plugin.Interceptor; 6 | import org.apache.ibatis.plugin.Intercepts; 7 | import org.apache.ibatis.plugin.Invocation; 8 | import org.apache.ibatis.plugin.Plugin; 9 | import org.apache.ibatis.plugin.Signature; 10 | import org.apache.ibatis.session.ResultHandler; 11 | import org.apache.ibatis.session.RowBounds; 12 | 13 | import java.util.Properties; 14 | 15 | @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), 16 | @Signature(type = Executor.class, method = "query", 17 | args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) 18 | public class MybatisInterceptor implements Interceptor { 19 | 20 | public Object intercept(final Invocation invocation) throws Throwable { 21 | final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; 22 | Object returnValue = null; 23 | final long start = System.currentTimeMillis(); 24 | returnValue = invocation.proceed(); 25 | final long end = System.currentTimeMillis(); 26 | 27 | final String sqlId = mappedStatement.getId(); 28 | final int lastIndex = sqlId.lastIndexOf('.'); 29 | final String className = sqlId.substring(0, lastIndex); 30 | final String methodName = sqlId.substring(lastIndex + 1); 31 | Tracer.getInstance().addBinaryAnnotation(className, methodName, (int) (end - start)); 32 | 33 | return returnValue; 34 | } 35 | 36 | public Object plugin(final Object target) { 37 | return Plugin.wrap(target, this); 38 | } 39 | 40 | public void setProperties(final Properties properties0) { 41 | //do nothing 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/capture/Sampler.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.capture; 2 | 3 | /** 4 | * 采样率适配器接口. 5 | */ 6 | public interface Sampler { 7 | boolean isSample(); 8 | 9 | void setSampleRate(int rate); 10 | } 11 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/capture/Traceable.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.capture; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Documented 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Target({ElementType.METHOD, ElementType.TYPE}) 12 | public @interface Traceable { 13 | /** 14 | * TRACE level of logging. 15 | */ 16 | @SuppressWarnings("PMD.RedundantFieldInitializer") 17 | int TRACE = 0; 18 | 19 | /** 20 | * DEBUG level of logging. 21 | */ 22 | int DEBUG = 1; 23 | 24 | /** 25 | * INFO level of logging. 26 | */ 27 | int INFO = 2; 28 | 29 | /** 30 | * WARN level of logging. 31 | */ 32 | int WARN = 3; 33 | 34 | /** 35 | * ERROR level of logging. 36 | */ 37 | int ERROR = 4; 38 | 39 | /** 40 | * Level of logging. 41 | */ 42 | int value() default Traceable.INFO; 43 | } 44 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/capture/TraceableAop.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.capture; 2 | 3 | import com.yirendai.infra.cicada.entity.trace.Endpoint; 4 | import com.yirendai.infra.cicada.entity.trace.Span; 5 | import com.yirendai.infra.cicada.utils.IpUtils; 6 | import com.yirendai.infra.cicada.utils.SpringContextUtil; 7 | 8 | import org.aspectj.lang.ProceedingJoinPoint; 9 | import org.aspectj.lang.annotation.Around; 10 | import org.aspectj.lang.annotation.Aspect; 11 | 12 | @Aspect 13 | public class TraceableAop { 14 | 15 | private static final String DEFAULT_APP_NAME = "traceable"; 16 | 17 | @Around("execution(* *(..)) && " 18 | + "(@within(com.yirendai.infra.cicada.capture.Traceable) ||" 19 | + " @annotation(com.yirendai.infra.cicada.capture.Traceable))") 20 | public Object around(final ProceedingJoinPoint point) throws java.lang.Throwable { 21 | final long start = System.currentTimeMillis(); 22 | final String localIp = IpUtils.getRealIpWithStaticCache(); 23 | final int localPort = 0; 24 | final Endpoint endpoint = new Endpoint(localIp, localPort); 25 | final String className = point.getTarget().getClass().getCanonicalName(); 26 | final String methodName = point.getSignature().getName(); 27 | final String appName = SpringContextUtil.getAppName(DEFAULT_APP_NAME); 28 | 29 | final Tracer tracer = Tracer.getInstance(); 30 | final Span parentSpan = tracer.getParentSpan(); 31 | final boolean createSpan = parentSpan == null; 32 | 33 | Span span = null; 34 | if (createSpan) { 35 | final Span traceCtx = tracer.getAndRemoveTraceCtx(); 36 | if (traceCtx != null) { 37 | final String traceId = traceCtx.getTraceId(); 38 | final String pid = traceCtx.getParentId(); 39 | final String id = traceCtx.getId(); 40 | final boolean sample = traceId != null; 41 | span = tracer.genSpan(appName, className, methodName, traceId, pid, id, sample); 42 | } else { 43 | span = tracer.newSpan(appName, className, methodName); 44 | } 45 | 46 | tracer.serverReceiveRecord(span, endpoint, start); 47 | } 48 | 49 | Object result = null; 50 | try { 51 | result = point.proceed(); 52 | } catch (Exception ex) { 53 | if (createSpan) { 54 | span.addException(className, methodName, ex, endpoint); 55 | } else { 56 | tracer.addBinaryAnnotation(className, methodName, ex); 57 | } 58 | 59 | throw ex; 60 | } finally { 61 | final long end = System.currentTimeMillis(); 62 | if (createSpan) { 63 | tracer.serverSendRecord(span, endpoint, end); 64 | } else { 65 | tracer.addBinaryAnnotation(className, methodName, (int) (end - start)); 66 | } 67 | } 68 | 69 | return result; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/capture/TracerUtils.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.capture; 2 | 3 | import com.alibaba.dubbo.common.utils.StringUtils; 4 | 5 | final class TracerUtils { 6 | public static final String TRACE_ID = "traceId"; 7 | public static final String SPAN_ID = "spanId"; 8 | public static final String PARENT_SPAN_ID = "parentId"; 9 | public static final String SAMPLE = "isSample"; 10 | 11 | private TracerUtils() {} 12 | 13 | public static Long getAttachmentLong(final String value) { 14 | Long retLong = null; 15 | if (!StringUtils.isBlank(value)) { 16 | retLong = Long.valueOf(value); 17 | } 18 | 19 | return retLong; 20 | } 21 | 22 | public static Boolean getAttachmentBoolean(final String value) { 23 | Boolean ret = Boolean.FALSE; 24 | if (value != null) { 25 | ret = Boolean.valueOf(value); 26 | } 27 | 28 | return ret; 29 | } 30 | 31 | public static Integer getAttachmentInteger(final String value) { 32 | Integer ret = null; 33 | if (!StringUtils.isBlank(value)) { 34 | ret = Integer.valueOf(value); 35 | } 36 | 37 | return ret; 38 | } 39 | 40 | public static int getAttachmentInt(final String value) { 41 | int ret = 0; 42 | if (!StringUtils.isBlank(value)) { 43 | ret = Integer.valueOf(value); 44 | } 45 | 46 | return ret; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/config/CicadaConfig.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.config; 2 | 3 | import com.yirendai.infra.cicada.transfer.TransferEngine; 4 | import com.yirendai.infra.cicada.utils.SpringContextUtil; 5 | 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class CicadaConfig { 12 | 13 | @Value("${cicada.url}") 14 | private String url; 15 | 16 | @Value("${cicada.sampleRate:100}") 17 | private int sampleRate; 18 | 19 | @Value("${cicada.connectTimeout:100}") 20 | private int connectTimeout; 21 | 22 | @Value("${cicada.soTimeout:100}") 23 | private int soTimeout; 24 | 25 | @Value("${cicada.batchSize:32}") 26 | private int batchSize; 27 | 28 | @Value("${cicada.bufferSize:1024}") 29 | private int bufferSize; 30 | 31 | @Value("${cicada.tpsLimit:2048}") 32 | private int tpsLimit; 33 | 34 | @Bean(name = "transferEngine", initMethod = "start") 35 | public TransferEngine transferEngine() { 36 | final TransferEngine transferEngine = new TransferEngine(url); 37 | 38 | transferEngine.setSampleRate(sampleRate); 39 | transferEngine.setConnectTimeout(connectTimeout); 40 | transferEngine.setSoTimeout(soTimeout); 41 | transferEngine.setBatchSize(batchSize); 42 | transferEngine.setBufferSize(bufferSize); 43 | transferEngine.setTpsLimit(tpsLimit); 44 | 45 | return transferEngine; 46 | } 47 | 48 | @Bean 49 | public SpringContextUtil springContextUtil() { 50 | return new SpringContextUtil(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/DeliverService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer; 2 | 3 | import com.yirendai.infra.cicada.entity.trace.Span; 4 | 5 | import java.util.List; 6 | 7 | public interface DeliverService { 8 | boolean deliver(Span span); 9 | 10 | boolean deliver(List spanList); 11 | } 12 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/Transfer.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer; 2 | 3 | import com.yirendai.infra.cicada.entity.trace.Span; 4 | 5 | public interface Transfer { 6 | boolean isReady(); 7 | 8 | boolean isServiceReady(String serviceName); 9 | 10 | void start() throws Exception; 11 | 12 | void cancel(); 13 | 14 | void asyncSend(Span span); 15 | } 16 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/TransferEngine.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer; 2 | 3 | import com.yirendai.infra.cicada.capture.CicadaDubboFilter; 4 | import com.yirendai.infra.cicada.capture.Tracer; 5 | import com.yirendai.infra.cicada.transfer.disruptor.DisruptorTransfer; 6 | import com.yirendai.infra.cicada.transfer.disruptor.SpanEventHandler; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | public class TransferEngine { 13 | 14 | private static final Logger LOGGER = LoggerFactory.getLogger(TransferEngine.class); 15 | 16 | private final String url; 17 | private int sampleRate = 100; 18 | private int connectTimeout = 100; 19 | private int soTimeout = 100; 20 | private int batchSize = 32; 21 | private int bufferSize = 2 ^ 10; 22 | private int tpsLimit = 2048; 23 | 24 | public TransferEngine(final String url) { 25 | this.url = url; 26 | } 27 | 28 | public void setSampleRate(final int sampleRate) { 29 | if (sampleRate >= 0) { 30 | this.sampleRate = sampleRate; 31 | } 32 | } 33 | 34 | public void setConnectTimeout(final int connectTimeout) { 35 | if (connectTimeout > 0) { 36 | this.connectTimeout = connectTimeout; 37 | } 38 | } 39 | 40 | public void setSoTimeout(final int soTimeout) { 41 | if (soTimeout > 0) { 42 | this.soTimeout = soTimeout; 43 | } 44 | } 45 | 46 | public void setBatchSize(final int batchSize) { 47 | if (batchSize > 0) { 48 | this.batchSize = batchSize; 49 | } 50 | } 51 | 52 | public void setBufferSize(final int bufferSize) { 53 | if (bufferSize > 0) { 54 | this.bufferSize = bufferSize; 55 | } 56 | } 57 | 58 | public void setTpsLimit(final int tpsLimit) { 59 | if (tpsLimit > 0) { 60 | this.tpsLimit = tpsLimit; 61 | } 62 | } 63 | 64 | public void start() { 65 | if (StringUtils.isBlank(url)) { 66 | LOGGER.error("url({}) can't be blank!", url); 67 | throw new java.lang.IllegalArgumentException("transfer url not defined"); 68 | } 69 | 70 | if (sampleRate <= 0 || connectTimeout <= 0 || soTimeout <= 0 || batchSize <= 0 || bufferSize <= 0 71 | || tpsLimit <= 0) { 72 | LOGGER.error("sampleRate:{},connectTimeout:{},soTimeout:{},batchSize:{},bufferSize:{},tpsLimit:{} must > 0", 73 | sampleRate, connectTimeout, soTimeout, batchSize, bufferSize, tpsLimit); 74 | throw new java.lang.IllegalArgumentException( 75 | "sampleRate,connectTimeout,soTimeout,batchSize,bufferSize,tpsLimit must > 0"); 76 | } 77 | 78 | final SpanEventHandler eventHandler = new SpanEventHandler(url, connectTimeout, soTimeout, batchSize, tpsLimit); 79 | final Transfer transfer = new DisruptorTransfer(eventHandler, bufferSize); 80 | final Tracer tracer = Tracer.getInstance(); 81 | tracer.setSampleRate(sampleRate); 82 | tracer.setTransfer(transfer); 83 | CicadaDubboFilter.setTracer(tracer); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/disruptor/DisruptorTransfer.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer.disruptor; 2 | 3 | import com.lmax.disruptor.RingBuffer; 4 | import com.lmax.disruptor.dsl.Disruptor; 5 | import com.yirendai.infra.cicada.entity.trace.Span; 6 | import com.yirendai.infra.cicada.transfer.Transfer; 7 | 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.ThreadFactory; 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | 12 | public class DisruptorTransfer implements Transfer { 13 | 14 | private static final int DEFAULT_BUFFER_SIZE = 1024; 15 | 16 | private final AtomicBoolean ready = new AtomicBoolean(false); 17 | 18 | private Disruptor disruptor; 19 | 20 | private SpanEventProducer producer; 21 | 22 | public DisruptorTransfer(final SpanEventHandler spanEventHandler) { 23 | this(spanEventHandler, DEFAULT_BUFFER_SIZE); 24 | } 25 | 26 | @SuppressWarnings("unchecked") 27 | public DisruptorTransfer(final SpanEventHandler spanEventHandler, final int buffSize) { 28 | // Executor executor = Executors.newCachedThreadPool(); 29 | final ThreadFactory threadFactory = Executors.defaultThreadFactory(); 30 | 31 | // The factory for the event 32 | final SpanEventFactory factory = new SpanEventFactory(); 33 | 34 | // Specify the size of the ring buffer, must be power of 2. 35 | final int bufferSize = buffSize; 36 | 37 | // Construct the Disruptor 38 | disruptor = new Disruptor(factory, bufferSize, threadFactory); 39 | 40 | // Connect the handler 41 | // disruptor.handleEventsWith(new 42 | // SpanEventHandler("http://localhost:9080/upload")); 43 | disruptor.handleEventsWith(spanEventHandler); 44 | 45 | // Start the Disruptor, starts all threads running 46 | disruptor.start(); 47 | 48 | final RingBuffer ringBuffer = disruptor.getRingBuffer(); 49 | producer = new SpanEventProducer(ringBuffer); 50 | } 51 | 52 | public boolean isReady() { 53 | return ready.get(); 54 | } 55 | 56 | public boolean isServiceReady(final String serviceName) { 57 | return ready.get(); 58 | } 59 | 60 | public void start() throws Exception { 61 | // do nothing 62 | } 63 | 64 | public void cancel() { 65 | disruptor.shutdown(); 66 | } 67 | 68 | public void asyncSend(final Span span) { 69 | producer.onData(span); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/disruptor/SpanEvent.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer.disruptor; 2 | 3 | import com.yirendai.infra.cicada.entity.trace.Span; 4 | 5 | public class SpanEvent { 6 | private Span span; 7 | 8 | public void set(final Span span) { 9 | this.span = span; 10 | } 11 | 12 | public Span get() { 13 | return this.span; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/disruptor/SpanEventFactory.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer.disruptor; 2 | 3 | import com.lmax.disruptor.EventFactory; 4 | 5 | public class SpanEventFactory implements EventFactory { 6 | public SpanEvent newInstance() { 7 | return new SpanEvent(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/disruptor/SpanEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer.disruptor; 2 | 3 | import com.lmax.disruptor.EventHandler; 4 | import com.yirendai.infra.cicada.entity.trace.Span; 5 | import com.yirendai.infra.cicada.transfer.DeliverService; 6 | import com.yirendai.infra.cicada.transfer.impl.HttpPostDeliverService; 7 | 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class SpanEventHandler implements EventHandler { 16 | 17 | private static final Logger LOGGER = LoggerFactory.getLogger(SpanEventHandler.class); 18 | 19 | private final List spanList = new ArrayList(); 20 | 21 | private static final int DEFAULT_CONNECT_TIMEOUT = 5000; 22 | private static final int DEFAULT_SO_TIMEOUT = 5000; 23 | private static final int DEFAULT_BATCH_SIZE = 32; 24 | private static final int DEFAULT_TPS_LIMIT = 2048; 25 | 26 | private DeliverService transferService; 27 | private int batchSize = DEFAULT_BATCH_SIZE; 28 | private int tpsLimit = DEFAULT_TPS_LIMIT; 29 | 30 | private long lastRecordTime; 31 | private int spanNum; 32 | private int dropNum; 33 | 34 | public SpanEventHandler(final String url) { 35 | this(url, DEFAULT_CONNECT_TIMEOUT, DEFAULT_SO_TIMEOUT, DEFAULT_BATCH_SIZE, DEFAULT_TPS_LIMIT); 36 | lastRecordTime = System.currentTimeMillis() / 1000; 37 | } 38 | 39 | public SpanEventHandler(final String url, final int connectTimeout, final int soTimeout, final int batchSize, 40 | final int tpsLimit) { 41 | if (StringUtils.isBlank(url)) { 42 | LOGGER.error("url shoud not empty!"); 43 | throw new IllegalArgumentException("url shoud not empty!"); 44 | } 45 | 46 | int finConnectTimeout = connectTimeout; 47 | int finSoTimeout = soTimeout; 48 | 49 | if (finConnectTimeout <= 0) { 50 | finConnectTimeout = DEFAULT_CONNECT_TIMEOUT; 51 | } 52 | 53 | if (finSoTimeout <= 0) { 54 | finSoTimeout = DEFAULT_SO_TIMEOUT; 55 | } 56 | 57 | transferService = new HttpPostDeliverService(url, finConnectTimeout, finSoTimeout); 58 | 59 | if (batchSize > 0) { 60 | this.batchSize = batchSize; 61 | } else { 62 | this.batchSize = DEFAULT_BATCH_SIZE; 63 | } 64 | 65 | this.tpsLimit = tpsLimit; 66 | if (this.tpsLimit <= 0) { 67 | this.tpsLimit = DEFAULT_TPS_LIMIT; 68 | } 69 | } 70 | 71 | public void onEvent(final SpanEvent spanEvent, final long sequence, final boolean endOfBatch) throws Exception { 72 | // LOGGER.info("receiveMsg:" + JSON.toJSONString(spanEvent.get())); 73 | 74 | final long currentTime = System.currentTimeMillis() / 1000; 75 | 76 | if (currentTime != lastRecordTime) { 77 | lastRecordTime = currentTime; 78 | spanNum = 1; 79 | if (dropNum > 0) { 80 | LOGGER.warn("too fast,drop some message!{}", dropNum); 81 | dropNum = 0; 82 | } 83 | } else { 84 | spanNum++; 85 | if (spanNum > tpsLimit) { 86 | dropNum++; 87 | return; 88 | } 89 | } 90 | 91 | try { 92 | final Span span = spanEvent.get(); 93 | spanList.add(span); 94 | 95 | if (endOfBatch || spanList.size() >= batchSize) { 96 | transferService.deliver(spanList); 97 | spanList.clear(); 98 | } 99 | 100 | } catch (Exception ex) { 101 | LOGGER.error("CreateHttpConnection error", ex); 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/disruptor/SpanEventProducer.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer.disruptor; 2 | 3 | import com.lmax.disruptor.RingBuffer; 4 | import com.yirendai.infra.cicada.entity.trace.Span; 5 | 6 | public class SpanEventProducer { 7 | private final RingBuffer ringBuffer; 8 | 9 | public SpanEventProducer(final RingBuffer ringBuffer) { 10 | this.ringBuffer = ringBuffer; 11 | } 12 | 13 | public void onData(final Span span) { 14 | final long sequence = ringBuffer.next(); 15 | try { 16 | final SpanEvent event = ringBuffer.get(sequence); 17 | event.set(span); 18 | } finally { 19 | ringBuffer.publish(sequence); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/transfer/impl/HttpPostDeliverService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.transfer.impl; 2 | 3 | import com.alibaba.dubbo.common.utils.CollectionUtils; 4 | import com.alibaba.fastjson.JSON; 5 | import com.yirendai.infra.cicada.entity.trace.Span; 6 | import com.yirendai.infra.cicada.transfer.DeliverService; 7 | 8 | import org.apache.http.HttpResponse; 9 | import org.apache.http.client.config.RequestConfig; 10 | import org.apache.http.client.methods.HttpPost; 11 | import org.apache.http.concurrent.FutureCallback; 12 | import org.apache.http.entity.StringEntity; 13 | import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; 14 | import org.apache.http.impl.nio.client.HttpAsyncClients; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | public class HttpPostDeliverService implements DeliverService { 22 | 23 | private static final Logger LOGGER = LoggerFactory.getLogger(HttpPostDeliverService.class); 24 | 25 | // private CloseableHttpClient httpClient; 26 | private final CloseableHttpAsyncClient httpClient; 27 | private final HttpPost httpPost; 28 | 29 | public HttpPostDeliverService(final String postUrl, final int connectTimeout, final int soTimeout) { 30 | httpClient = HttpAsyncClients.createDefault(); 31 | httpClient.start(); 32 | 33 | httpPost = new HttpPost(postUrl); 34 | final RequestConfig requestConfig = 35 | RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(soTimeout).build(); 36 | httpPost.setConfig(requestConfig); 37 | 38 | httpPost.setHeader("Content-type", "application/json"); 39 | httpPost.setHeader("Content-Type", "text/html;charset=UTF-8"); 40 | } 41 | 42 | public boolean deliver(final Span span) { 43 | boolean ret = false; 44 | if (span == null) { 45 | LOGGER.error("no span!"); 46 | ret = false; 47 | } else { 48 | final List spanList = new ArrayList(); 49 | spanList.add(span); 50 | 51 | ret = deliver(spanList); 52 | } 53 | 54 | return ret; 55 | } 56 | 57 | public boolean deliver(final List spanList) { 58 | boolean ret = false; 59 | 60 | if (CollectionUtils.isEmpty(spanList)) { 61 | LOGGER.error("spanList is Empty!"); 62 | ret = false; 63 | } else { 64 | if (httpClient == null || httpPost == null) { 65 | LOGGER.error("httpClient({}) or httpPost({}) is null", httpClient, httpPost); 66 | ret = false; 67 | } else { 68 | final long startTime = System.currentTimeMillis(); 69 | 70 | final int spanSize = spanList.size(); 71 | final String spanListJson = JSON.toJSONString(spanList); 72 | final StringEntity postingString = new StringEntity(spanListJson, "utf-8"); 73 | 74 | httpPost.setEntity(postingString); 75 | httpClient.execute(httpPost, new FutureCallback() { 76 | public void completed(final HttpResponse response) { 77 | if (LOGGER.isDebugEnabled()) { 78 | LOGGER.debug("[push({})] [http_status:200] [spanSize:{}] [{}ms]", spanListJson, spanSize, 79 | (System.currentTimeMillis() - startTime)); 80 | } 81 | } 82 | 83 | public void failed(final Exception ex) { 84 | LOGGER.error("[push({})] [{}] [error:{}]", httpPost.getURI(), spanListJson, ex); 85 | } 86 | 87 | public void cancelled() { 88 | LOGGER.error("[push({})] [http_status:cancelled] [{}ms]", spanListJson, 89 | (System.currentTimeMillis() - startTime)); 90 | } 91 | }); 92 | 93 | ret = true; 94 | } 95 | } 96 | 97 | return ret; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /cicada-client/src/main/java/com/yirendai/infra/cicada/utils/SpringContextUtil.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.utils; 2 | 3 | import com.alibaba.dubbo.config.ApplicationConfig; 4 | 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.springframework.beans.BeansException; 7 | import org.springframework.beans.factory.NoSuchBeanDefinitionException; 8 | import org.springframework.context.ApplicationContext; 9 | import org.springframework.context.ApplicationContextAware; 10 | 11 | public class SpringContextUtil implements ApplicationContextAware { 12 | private static ApplicationContext applicationContext; // Spring应用上下文环境 13 | 14 | /** 15 | * 实现ApplicationContextAware接口的回调方法,设置上下文环境. 16 | * 17 | */ 18 | public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { 19 | SpringContextUtil.applicationContext = applicationContext; 20 | } 21 | 22 | public static ApplicationContext getApplicationContext() { 23 | return applicationContext; 24 | } 25 | 26 | 27 | 28 | 29 | /** 30 | * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true. 31 | * 32 | */ 33 | public static boolean containsBean(final String name) { 34 | return applicationContext.containsBean(name); 35 | } 36 | 37 | /** 38 | * 判断以给定名字注册的bean定义是一个singleton还是一个prototype. 39 | * 40 | * @throws NoSuchBeanDefinitionException - 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常 41 | */ 42 | public static boolean isSingleton(final String name) throws NoSuchBeanDefinitionException { 43 | return applicationContext.isSingleton(name); 44 | } 45 | 46 | /** 47 | * @return Class 注册对象的类型. 48 | */ 49 | public static Class getType(final String name) throws NoSuchBeanDefinitionException { 50 | return applicationContext.getType(name); 51 | } 52 | 53 | /** 54 | * 如果给定的bean名字在bean定义中有别名,则返回这些别名. 55 | * 56 | */ 57 | public static String[] getAliases(final String name) throws NoSuchBeanDefinitionException { 58 | return applicationContext.getAliases(name); 59 | } 60 | 61 | /** 62 | * 获取对象. 63 | * 64 | */ 65 | public static Object getBean(final String name) throws BeansException { 66 | return applicationContext.getBean(name); 67 | } 68 | 69 | /** 70 | * 获取类型为requiredType的对象 如果bean不能被类型转换,相应的异常将会被抛出(BeanNotOfRequiredTypeException). 71 | * 72 | * @param name bean注册名 73 | * @param requiredType 返回对象类型 74 | * @return Object 返回requiredType类型对象 75 | */ 76 | public static T getBean(final String name, final Class requiredType) throws BeansException { 77 | return applicationContext.getBean(name, requiredType); 78 | } 79 | 80 | /** 81 | * 获取对象. 82 | * 83 | * @return Object 一个以所给名字注册的bean的实例 84 | */ 85 | public static T getBean(final Class clz) throws BeansException { 86 | return applicationContext.getBean(clz); 87 | } 88 | 89 | /** 90 | * 获取对象. 91 | * 92 | * @return Object 一个以所给名字注册的bean的实例 93 | */ 94 | public static T getBean(final Class clz, final T defaultValue) { 95 | T ret = null; 96 | try { 97 | ret = applicationContext.getBean(clz); 98 | } catch (BeansException ex) { 99 | ret = defaultValue; 100 | } 101 | 102 | return ret; 103 | } 104 | 105 | public static String getAppName(final String defaultValue) { 106 | String retValue = null; 107 | final ApplicationConfig application = getBean(ApplicationConfig.class, null); 108 | if (application != null) { 109 | retValue = application.getName(); 110 | } 111 | 112 | if (StringUtils.isBlank(retValue) && applicationContext != null) { 113 | retValue = applicationContext.getApplicationName(); 114 | } 115 | 116 | if (StringUtils.isBlank(retValue)) { 117 | retValue = defaultValue; 118 | } 119 | 120 | return retValue; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /cicada-client/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter: -------------------------------------------------------------------------------- 1 | cicada=com.yirendai.infra.cicada.capture.CicadaDubboFilter 2 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/com/yirendai/infra/cicada/BenchmarkTransfer.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import com.yirendai.infra.cicada.entity.trace.Span; 4 | import com.yirendai.infra.cicada.transfer.Transfer; 5 | import com.yirendai.infra.cicada.transfer.disruptor.DisruptorTransfer; 6 | import com.yirendai.infra.cicada.transfer.disruptor.SpanEventHandler; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | import java.util.concurrent.atomic.AtomicLong; 13 | 14 | /** 15 | * 压测工具,可以用来测试日志传送的TPS大小,协助设置TPS最大值. 16 | * 17 | * @author zpc 18 | */ 19 | public final class BenchmarkTransfer { 20 | private static final Logger LOGGER = LoggerFactory.getLogger(BenchmarkTransfer.class); 21 | 22 | private BenchmarkTransfer() {} 23 | 24 | @SuppressWarnings({"PMD.DoNotUseThreads", "PMD.AvoidInstantiatingObjectsInLoops"}) 25 | public static void main(final String... args) { 26 | if (args.length <= 0) { 27 | System.err.println("java BenchmarkTransfer "); 28 | return; 29 | } 30 | 31 | final String url = args[0]; 32 | final int connectTimeout = 100; 33 | final int soTimeout = 100; 34 | final int batchSize = 32; 35 | final int bufferSize = 2 ^ 10; 36 | final int tpsLimit = 2048; 37 | final SpanEventHandler eventHandler = new SpanEventHandler(url, connectTimeout, soTimeout, batchSize, tpsLimit); 38 | final Transfer transfer = new DisruptorTransfer(eventHandler, bufferSize); 39 | 40 | final long startTime = System.currentTimeMillis(); 41 | final AtomicLong num = new AtomicLong(0); 42 | 43 | for (int i = 0; i < 11; i++) { 44 | new Thread(new Runnable() { 45 | public void run() { 46 | while (true) { 47 | try { 48 | num.compareAndSet(Integer.MAX_VALUE, 0); 49 | final long id = num.incrementAndGet(); 50 | final Span span = new Span(); 51 | span.setTraceId(Long.toString(id)); 52 | transfer.asyncSend(span); 53 | 54 | TimeUnit.MILLISECONDS.sleep(10); 55 | } catch (Exception ex) { 56 | LOGGER.error("error!", ex); 57 | } 58 | } 59 | } 60 | }, "productThread-" + i).start(); 61 | } 62 | 63 | new Thread(new Runnable() { 64 | public void run() { 65 | while (true) { 66 | try { 67 | TimeUnit.SECONDS.sleep(1); 68 | } catch (InterruptedException ex) { 69 | LOGGER.error("error!", ex); 70 | } 71 | final long duration = System.currentTimeMillis() - startTime; 72 | LOGGER.error("TPS:" + (num.get() * 1000 / duration)); 73 | } 74 | } 75 | 76 | }, "staticsThead").start(); 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/com/yirendai/infra/cicada/ExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import com.alibaba.dubbo.remoting.ExecutionException; 4 | import com.alibaba.dubbo.remoting.TimeoutException; 5 | import com.alibaba.dubbo.rpc.RpcException; 6 | import com.alibaba.fastjson.JSON; 7 | 8 | public final class ExceptionTest { 9 | private ExceptionTest(){} 10 | 11 | public static void main(final String... args) { 12 | final ExecutionException ee = new ExecutionException(null, null, "hee"); 13 | 14 | System.err.println("ee:" + JSON.toJSONString(ee)); 15 | System.err.println("em:" + ee.getMessage()); 16 | System.err.println("em-1:" + JSON.toJSONString(ee.getClass())); 17 | System.err.println("em-2:" + ee.getClass().getCanonicalName()); 18 | 19 | final RpcException re = new RpcException("sx"); 20 | System.err.println("re:" + JSON.toJSONString(re)); 21 | System.err.println("rem:" + re.getMessage()); 22 | 23 | final TimeoutException te = new TimeoutException(true, null, "sss"); 24 | System.err.println("te:" + JSON.toJSONString(te)); 25 | 26 | @SuppressWarnings("PMD.AvoidThrowingNullPointerException") 27 | final Throwable tb = new NullPointerException("null"); 28 | System.err.println("tb:" + JSON.toJSONString(tb)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/com/yirendai/infra/cicada/HttpPostDeliverServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import com.yirendai.infra.cicada.entity.trace.Span; 4 | import com.yirendai.infra.cicada.transfer.impl.HttpPostDeliverService; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public final class HttpPostDeliverServiceTest { 10 | private static final Logger LOGGER = LoggerFactory.getLogger(HttpPostDeliverServiceTest.class); 11 | 12 | private HttpPostDeliverServiceTest(){} 13 | 14 | public static void main(final String... args) { 15 | final String url = "http://localhost:9080/upload"; 16 | final int connectTimeout = 10000; 17 | final int soTimeout = 10000; 18 | 19 | final HttpPostDeliverService service = new HttpPostDeliverService(url, connectTimeout, soTimeout); 20 | 21 | final long startTime = System.currentTimeMillis(); 22 | final Span span = new Span(); 23 | span.setId("1"); 24 | for (int i = 0; i < 10; i++) { 25 | service.deliver(span); 26 | } 27 | 28 | LOGGER.info("time:" + (System.currentTimeMillis() - startTime)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/demo/consumer/DemoConsumer.java: -------------------------------------------------------------------------------- 1 | package demo.consumer; 2 | 3 | import demo.provider.DemoService; 4 | 5 | import org.springframework.context.support.ClassPathXmlApplicationContext; 6 | 7 | import java.util.Random; 8 | 9 | public final class DemoConsumer { 10 | 11 | private DemoConsumer() {} 12 | 13 | @SuppressWarnings("PMD.AvoidPrintStackTrace") 14 | public static void main(final String... args) throws Exception { 15 | 16 | try { 17 | final ClassPathXmlApplicationContext context = 18 | new ClassPathXmlApplicationContext(new String[] {"dubbo-demo-consumer.xml", "/cicada-config.xml"}); 19 | context.start(); 20 | final DemoService service = (DemoService) context.getBean("demoService"); // 获取远程服务代理 21 | 22 | final Random random = new Random(); 23 | int totalNum = 1000000; 24 | while (totalNum > 0) { 25 | final String str = service.sayHello("hello~"); 26 | System.out.println("message:" + str); 27 | final long time = 0 + random.nextInt(2000); 28 | Thread.sleep(time); 29 | totalNum--; 30 | } 31 | 32 | context.close(); 33 | } catch (Exception ex) { 34 | ex.printStackTrace(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/demo/provider/DemoProvider.java: -------------------------------------------------------------------------------- 1 | package demo.provider; 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext; 4 | 5 | public final class DemoProvider { 6 | 7 | private DemoProvider(){} 8 | 9 | public static void main(final String... args) throws Exception { 10 | final ClassPathXmlApplicationContext context = 11 | new ClassPathXmlApplicationContext(new String[] {"dubbo-demo-provider.xml", "/cicada-config.xml"}); 12 | context.start(); 13 | System.in.read(); // 按任意键退出 14 | context.close(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/demo/provider/DemoService.java: -------------------------------------------------------------------------------- 1 | package demo.provider; 2 | 3 | public interface DemoService { 4 | 5 | String sayHello(String name); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/demo/provider/DemoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package demo.provider; 2 | 3 | import com.alibaba.dubbo.rpc.RpcContext; 4 | 5 | import demo.provider2.DemoService2; 6 | 7 | public class DemoServiceImpl implements DemoService { 8 | 9 | private DemoService2 demoService2; 10 | 11 | public void setDemoService2(final DemoService2 demoService2) { 12 | this.demoService2 = demoService2; 13 | } 14 | 15 | public String sayHello(final String name) { 16 | System.out.println(demoService2.sayWorld(name)); 17 | // System.out.println("[" + new SimpleDateFormat("HH:mm:ss").format(new 18 | // Date()) + "] Hello " + name 19 | // + ", request from consumer: " + 20 | // RpcContext.getContext().getRemoteAddress()); 21 | return "Hello " + name + ", response form provider: " + RpcContext.getContext().getLocalAddress(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/demo/provider2/DemoProvider2.java: -------------------------------------------------------------------------------- 1 | package demo.provider2; 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext; 4 | 5 | public final class DemoProvider2 { 6 | 7 | private DemoProvider2(){} 8 | 9 | public static void main(final String... args) throws Exception { 10 | final ClassPathXmlApplicationContext context = 11 | new ClassPathXmlApplicationContext(new String[] {"dubbo-demo-provider2.xml", "/cicada-config.xml"}); 12 | context.start(); 13 | System.in.read(); // 按任意键退出 14 | context.close(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/demo/provider2/DemoService2.java: -------------------------------------------------------------------------------- 1 | package demo.provider2; 2 | 3 | public interface DemoService2 { 4 | 5 | String sayWorld(String name); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /cicada-client/src/test/java/demo/provider2/DemoServiceImpl2.java: -------------------------------------------------------------------------------- 1 | package demo.provider2; 2 | 3 | public class DemoServiceImpl2 implements DemoService2 { 4 | 5 | public String sayWorld(final String name) { 6 | return "world " + name; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /cicada-client/src/test/resources/cicada-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /cicada-client/src/test/resources/dubbo-demo-consumer.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /cicada-client/src/test/resources/dubbo-demo-provider.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /cicada-client/src/test/resources/dubbo-demo-provider2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /cicada-client/src/test/resources/dubbo.properties: -------------------------------------------------------------------------------- 1 | dubbo.application.name=cicada-example 2 | dubbo.application.owner=zpc 3 | dubbo.registry.protocol=zookeeper 4 | dubbo.registry.address=127.0.0.1:2181 5 | #ҵ��ϵͳ����cicada��� 6 | #�����ṩ�� 7 | dubbo.service.filter=cicada 8 | #��������� 9 | dubbo.reference.filter=cicada -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/Application.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import com.yirendai.infra.cicada.service.LogCollectService; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.ConfigurableApplicationContext; 9 | import org.springframework.scheduling.annotation.EnableAsync; 10 | 11 | @SpringBootApplication 12 | @EnableAsync 13 | public class Application { 14 | 15 | @Autowired 16 | private LogCollectService collector; 17 | 18 | private void run() { 19 | this.collector.start(); 20 | } 21 | 22 | public static void main(final String... args) { 23 | final ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); 24 | context.getBean(Application.class).run(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/ApplicationShutdown.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import com.yirendai.infra.cicada.service.LogCollectService; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.context.event.ContextClosedEvent; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class ApplicationShutdown implements ApplicationListener { 12 | 13 | @Autowired 14 | private LogCollectService collector; 15 | 16 | @Override 17 | public void onApplicationEvent(final ContextClosedEvent event) { 18 | collector.finish(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/config/CicadaCollectorProps.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.config; 2 | 3 | import lombok.Getter; 4 | 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Getter 9 | @Component 10 | public class CicadaCollectorProps { 11 | @Value("${elasticsearch.node.addr}") 12 | private String esNodeAddr; 13 | 14 | @Value("${elasticsearch.node.port}") 15 | private int esNodePort; 16 | 17 | @Value("${elasticsearch.cluster.name}") 18 | private String esClusterName; 19 | 20 | @Value("${elasticsearch.bulk.await.minutes}") 21 | private int esBulkAwaitMinutes; 22 | 23 | @Value("${elasticsearch.index.type.name}") 24 | private String esTypeName; 25 | 26 | @Value("${elasticsearch.index.span.prefix}") 27 | private String esSpanIndexPrefix; 28 | 29 | @Value("${elasticsearch.index.annotation.prefix}") 30 | private String esAnnotationIndexPrefix; 31 | 32 | @Value("${job.slot.range}") 33 | private int jobSlotRange; 34 | 35 | @Value("${trace.progress.file.path}") 36 | private String progressFilePath; 37 | 38 | @Value("${trace.log.root.dir}") 39 | private String traceLogRootDir; 40 | } 41 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/repository/TraceElasticRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.yirendai.infra.cicada.config.CicadaCollectorProps; 5 | import com.yirendai.infra.cicada.util.elastic.IndexManager; 6 | 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import org.elasticsearch.action.bulk.BulkProcessor; 10 | import org.elasticsearch.action.bulk.BulkRequest; 11 | import org.elasticsearch.action.bulk.BulkResponse; 12 | import org.elasticsearch.action.index.IndexRequest; 13 | import org.elasticsearch.client.transport.TransportClient; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Component; 16 | 17 | import java.util.List; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | @Slf4j 21 | @Component 22 | public class TraceElasticRepository { 23 | @Autowired 24 | private CicadaCollectorProps props; 25 | 26 | @Autowired 27 | private TransportClient client; 28 | 29 | @Autowired 30 | private IndexManager indexManager; 31 | 32 | public void upload(final String type, final List objects) { 33 | final String indexName = indexManager.getCurrentIndexName(type); 34 | final BulkProcessor bulkProcessor = BulkProcessor.builder(client, new BulkProcessor.Listener() { 35 | @Override 36 | public void beforeBulk(final long executionId, final BulkRequest request) { } 37 | 38 | @Override 39 | public void afterBulk(final long executionId, // 40 | final BulkRequest request, // 41 | final BulkResponse response) { 42 | if (response.hasFailures()) { 43 | log.error("failed index data; {}", response.buildFailureMessage()); 44 | } 45 | } 46 | 47 | @Override 48 | public void afterBulk(final long executionId, // 49 | final BulkRequest request, // 50 | final Throwable failure) { 51 | log.error("failed upload data: {}", failure.getCause()); 52 | } 53 | }).build(); 54 | 55 | // add all datas to bulkProcessor 56 | for (final T object : objects) { 57 | bulkProcessor.add(new IndexRequest(indexName, props.getEsTypeName()).source(JSON.toJSONString(object))); 58 | } 59 | 60 | try { 61 | bulkProcessor.awaitClose(props.getEsBulkAwaitMinutes(), TimeUnit.MINUTES); 62 | } catch (InterruptedException ex) { 63 | log.error("execute bulkProcessor interrupted, type {}, error msg: {}", indexName, ex); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/service/ElasticUploadService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.service; 2 | 3 | import com.yirendai.infra.cicada.entity.model.AnnotationModel; 4 | import com.yirendai.infra.cicada.entity.model.SpanModel; 5 | import com.yirendai.infra.cicada.repository.TraceElasticRepository; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.util.List; 11 | 12 | @Component 13 | public class ElasticUploadService { 14 | private static final String SPAN_TYPE_STR = "span"; 15 | private static final String ANNOTATION_TYPE_STR = "annotation"; 16 | 17 | @Autowired 18 | private TraceElasticRepository repo; 19 | 20 | public void upload(final List spans, final List annos) { 21 | repo.upload(SPAN_TYPE_STR, spans); 22 | repo.upload(ANNOTATION_TYPE_STR, annos); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/ServiceRegisterManager.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util; 2 | 3 | import com.yirendai.infra.cicada.service.MethodService; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | @Component 12 | public class ServiceRegisterManager { 13 | private final AppMapper mapper = new AppMapper(); 14 | 15 | @Autowired 16 | private MethodService methodService; 17 | 18 | public Map getRegisterInfo(final String appName, // 19 | final String serviceName, // 20 | final String methodName) { 21 | ServiceMapper serviceMapper = mapper.getServiceMapper(appName); 22 | if (serviceMapper == null) { 23 | serviceMapper = new ServiceMapper(); 24 | mapper.putServiceMapper(appName, serviceMapper); 25 | } 26 | 27 | MethodMapper methodMapper = serviceMapper.getMethodMapper(serviceName); 28 | if (methodMapper == null) { 29 | methodMapper = new MethodMapper(); 30 | serviceMapper.putMethodMapper(serviceName, methodMapper); 31 | } 32 | 33 | Map idMap = methodMapper.getIdMap(methodName); 34 | if (idMap == null) { 35 | idMap = methodService.getMethodIdMap(appName, serviceName, methodName); 36 | methodMapper.putIdMap(methodName, idMap); 37 | } 38 | 39 | return idMap; 40 | } 41 | 42 | private class MethodMapper { 43 | final Map> infoMap = new ConcurrentHashMap>(); 44 | 45 | final Map getIdMap(final String key) { 46 | return infoMap.get(key); 47 | } 48 | 49 | void putIdMap(final String key, final Map idMap) { 50 | infoMap.put(key, idMap); 51 | } 52 | } 53 | 54 | private class ServiceMapper { 55 | Map map = new ConcurrentHashMap(); 56 | 57 | MethodMapper getMethodMapper(final String key) { 58 | return map.get(key); 59 | } 60 | 61 | void putMethodMapper(final String key, final MethodMapper mapper) { 62 | map.put(key, mapper); 63 | } 64 | } 65 | 66 | private class AppMapper { 67 | Map map = new ConcurrentHashMap(); 68 | 69 | ServiceMapper getServiceMapper(final String key) { 70 | return map.get(key); 71 | } 72 | 73 | void putServiceMapper(final String key, final ServiceMapper mapper) { 74 | map.put(key, mapper); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/TraceChainModelGenerator.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util; 2 | 3 | import com.yirendai.infra.cicada.config.CicadaCollectorProps; 4 | import com.yirendai.infra.cicada.entity.model.AnnotationModel; 5 | import com.yirendai.infra.cicada.entity.model.SpanModel; 6 | import com.yirendai.infra.cicada.entity.trace.Annotation; 7 | import com.yirendai.infra.cicada.entity.trace.BinaryAnnotation; 8 | import com.yirendai.infra.cicada.entity.trace.Span; 9 | import com.yirendai.infra.cicada.utils.TraceUtil; 10 | 11 | import org.springframework.beans.BeanUtils; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.util.Map; 16 | 17 | /** 18 | * 调用链存储对象生成工具 针对日志读取的对象进行清洗,生成Trace/Span/Annotation的存储对象. 19 | * 20 | * @author Zecheng 21 | * 22 | */ 23 | @Component 24 | public class TraceChainModelGenerator { 25 | @Autowired 26 | private ServiceRegisterManager manager; 27 | 28 | @Autowired 29 | private CicadaCollectorProps props; 30 | 31 | public SpanModel genSpanModel(final Span span) { 32 | final SpanModel model; 33 | final int durationServer = TraceUtil.calcSpanDurationServer(span); 34 | if (durationServer < 0) { 35 | model = null; 36 | } else { 37 | model = new SpanModel(); 38 | BeanUtils.copyProperties(span, model); 39 | 40 | final Map idMap = 41 | manager.getRegisterInfo(span.getAppName(), span.getServiceName(), span.getMethodName()); 42 | model.setAppId(idMap.get("appId")); 43 | model.setServiceId(idMap.get("serviceId")); 44 | model.setMethodId(idMap.get("methodId")); 45 | model.setDurationServer(durationServer); 46 | 47 | final Annotation sr = TraceUtil.getSrAnnotation(span.getAnnotations()); 48 | if (sr != null) { 49 | model.setStartTime(sr.getTimestamp()); 50 | } 51 | model.calcSliceNo(props.getJobSlotRange()); 52 | } 53 | 54 | return model; 55 | } 56 | 57 | public AnnotationModel genAnnotationModel(final Span span, final Annotation anno) { 58 | final AnnotationModel model = new AnnotationModel(); 59 | BeanUtils.copyProperties(anno, model); 60 | 61 | model.setType(anno.getType().name()); 62 | model.setTraceId(span.getTraceId()); 63 | model.setSpanId(span.getId()); 64 | 65 | return model; 66 | } 67 | 68 | public AnnotationModel genAnnotationModel(final Span span, final BinaryAnnotation binAnno) { 69 | final AnnotationModel model = new AnnotationModel(); 70 | BeanUtils.copyProperties(binAnno, model); 71 | 72 | model.setType(binAnno.getType().name()); 73 | model.setTraceId(span.getTraceId()); 74 | model.setSpanId(span.getId()); 75 | 76 | return model; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/elastic/DayRotatedIndexManager.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util.elastic; 2 | 3 | import com.yirendai.infra.cicada.config.CicadaCollectorProps; 4 | import com.yirendai.infra.cicada.constants.DateTimeFormats; 5 | 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; 9 | import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse; 10 | import org.elasticsearch.client.transport.TransportClient; 11 | import org.elasticsearch.indices.IndexAlreadyExistsException; 12 | import org.joda.time.DateTime; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.stereotype.Component; 15 | 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.concurrent.ExecutionException; 19 | import java.util.concurrent.TimeUnit; 20 | import java.util.concurrent.TimeoutException; 21 | 22 | import javax.annotation.PostConstruct; 23 | 24 | @Slf4j 25 | @Component 26 | public class DayRotatedIndexManager implements IndexManager { 27 | private static final int TIMEOUT_SECOND_LIMITS = 5; 28 | private static final String SPAN_TYPE_STR = "span"; 29 | private static final String ANNOTATION_TYPE_STR = "annotation"; 30 | private static final String INDEX_CAT_CHARS = "_"; 31 | 32 | @Autowired 33 | private CicadaCollectorProps props; 34 | 35 | @Autowired 36 | private IndexConfigLoader indexConfigLoader; 37 | 38 | @Autowired 39 | private TransportClient client; 40 | 41 | private Map indexNameMap; 42 | 43 | @PostConstruct 44 | public void init() { 45 | this.indexNameMap = new HashMap(); 46 | this.indexNameMap.put(SPAN_TYPE_STR, this.props.getEsSpanIndexPrefix()); 47 | this.indexNameMap.put(ANNOTATION_TYPE_STR, this.props.getEsAnnotationIndexPrefix()); 48 | } 49 | 50 | public String getCurrentIndexName(final String type) { 51 | final String curIndexName = generateCurrentIndexName(type); 52 | if (!exists(curIndexName)) { 53 | createIndex(type, curIndexName); 54 | } 55 | 56 | return curIndexName; 57 | } 58 | 59 | private String generateCurrentIndexName(final String type) { 60 | final String dateStr = DateTime.now().toString(DateTimeFormats.FULL_DATE_ENGLISH); 61 | final String indexNamePrefix = indexNameMap.get(type); 62 | return indexNamePrefix + INDEX_CAT_CHARS + dateStr; 63 | } 64 | 65 | private boolean exists(final String indexName) { 66 | final IndicesExistsRequest req = new IndicesExistsRequest(indexName); 67 | IndicesExistsResponse resp = null; 68 | 69 | try { 70 | resp = client.admin().indices().exists(req).get(TIMEOUT_SECOND_LIMITS, TimeUnit.SECONDS); 71 | } catch (InterruptedException ex) { 72 | log.error("failed get index's exists status, indexName {}, error {}", indexName, ex); 73 | } catch (TimeoutException ex) { 74 | log.error("timeout when get index's exists status, indexName {}, error {}", indexName, ex); 75 | } catch (ExecutionException ex) { 76 | log.error("execution exception occured, indexName {}, error {}", indexName, ex); 77 | } 78 | 79 | return resp != null && resp.isExists(); 80 | } 81 | 82 | private void createIndex(final String type, final String indexName) { 83 | // 加载配置文件 84 | final String indexConfig = indexConfigLoader.load(type); 85 | 86 | // 创建索引 87 | try { 88 | client.admin().indices().prepareCreate(indexName).setSource(indexConfig).execute().actionGet(); 89 | } catch (IndexAlreadyExistsException ex) { 90 | log.error("conflict while create index: {}, it's not serious.", indexName); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/elastic/IndexConfigLoader.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util.elastic; 2 | 3 | import com.fasterxml.jackson.databind.JsonNode; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.io.InputStream; 11 | 12 | /** 13 | * 从配置文件加载elastic索引配置信息. 14 | * @author Zecheng 15 | */ 16 | @Slf4j 17 | @Component 18 | public class IndexConfigLoader { 19 | public static final String ROOTDIR = "/elastic/"; 20 | 21 | public String load(final String type) { 22 | final String path = ROOTDIR + type + ".settings"; 23 | 24 | InputStream in = null; 25 | JsonNode node = null; 26 | try { 27 | in = IndexConfigLoader.class.getResourceAsStream(path); 28 | node = new ObjectMapper().readTree(in); 29 | return node.toString(); 30 | } catch (Exception ex) { 31 | log.error("failed load config from path: {}, error: {}", path, ex); 32 | throw new RuntimeException("failed load index config from path: " + path); 33 | } finally { 34 | try { 35 | in.close(); 36 | } catch (Exception ex) { // 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/elastic/IndexManager.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util.elastic; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public interface IndexManager { 7 | String getCurrentIndexName(String type); 8 | } 9 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/progress/FileProgressRecorder.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util.progress; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.yirendai.infra.cicada.config.CicadaCollectorProps; 6 | 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.io.File; 14 | import java.io.FileNotFoundException; 15 | import java.io.IOException; 16 | import java.io.RandomAccessFile; 17 | 18 | 19 | /** 20 | * @brief 使用文件存取当前进度. 21 | * @author Zecheng 22 | */ 23 | @Slf4j 24 | @Component 25 | public class FileProgressRecorder implements ProgressRecorder { 26 | @Autowired 27 | private CicadaCollectorProps props; 28 | 29 | private RandomAccessFile file; 30 | 31 | private void mkdirs() { 32 | final String dirStr = StringUtils.substringBeforeLast(props.getProgressFilePath(), "/"); 33 | final File dir = new File(dirStr); 34 | if (!dir.exists()) { 35 | dir.mkdirs(); 36 | } 37 | } 38 | 39 | @Override 40 | public void set(final Progress record) { 41 | final String path = props.getProgressFilePath(); 42 | try { 43 | mkdirs(); 44 | file = new RandomAccessFile(path, "rw"); 45 | final String recordStr = JSON.toJSONString(record); 46 | file.setLength(0L); 47 | file.writeBytes(recordStr); 48 | } catch (FileNotFoundException ex) { 49 | log.error("file not exists: {}, error: {}", path, ex); 50 | } catch (IOException ex) { 51 | log.error("failed record to file: {}, error: {}", path, ex); 52 | } finally { 53 | if (file != null) { 54 | try { 55 | file.close(); 56 | } catch (IOException ex) { 57 | log.error("failed close file: {}, error: {}", path, ex); 58 | } 59 | } 60 | } 61 | } 62 | 63 | @Override 64 | public Progress get() { 65 | 66 | String line = null; 67 | Progress record = null; 68 | final String path = props.getProgressFilePath(); 69 | 70 | try { 71 | if (exists(path)) { 72 | file = new RandomAccessFile(path, "rw"); 73 | line = file.readLine(); 74 | if (!StringUtils.isBlank(line.trim())) { 75 | record = JSON.parseObject(line, Progress.class); 76 | } 77 | } 78 | } catch (FileNotFoundException ex) { 79 | log.error("file not exists: {}", path); 80 | } catch (IOException ex) { 81 | log.error("failed read record from file: {}, error: {}", path, ex); 82 | } catch (JSONException ex) { 83 | log.error("failed parse json str: {}, error: {}", line, ex); 84 | } finally { 85 | if (file != null) { 86 | try { 87 | file.close(); 88 | } catch (IOException ex) { 89 | log.error("failed close file: ", path); 90 | } 91 | } 92 | } 93 | 94 | return record; 95 | } 96 | 97 | private boolean exists(final String path) { 98 | final File ff = new File(path); 99 | return ff.exists(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/progress/MessageWasher.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util.progress; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public class MessageWasher { 7 | 8 | public String wash(String message) { 9 | return message.replace("\\x22", "\""); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/progress/Progress.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util.progress; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 进度信息. 9 | */ 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public class Progress { 14 | private String fileName; 15 | private long offset; 16 | 17 | @Override 18 | public String toString() { 19 | return "{fileName:" + fileName + ",offset:" + offset + "}"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cicada-collector/src/main/java/com/yirendai/infra/cicada/util/progress/ProgressRecorder.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util.progress; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public interface ProgressRecorder { 7 | /** 8 | * 记录进度. 9 | */ 10 | void set(Progress record); 11 | 12 | /** 13 | * 读取进度. 14 | */ 15 | Progress get(); 16 | } 17 | -------------------------------------------------------------------------------- /cicada-collector/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles.active: env_development 3 | datasource.driverClassName: com.p6spy.engine.spy.P6SpyDriver 4 | jpa: 5 | database: mysql 6 | properties.jadira.usertype.autoRegisterUserTypes: true 7 | generate-ddl: false 8 | hibernate.ddl-auto: none 9 | hibernate.naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy 10 | # properties.hibernate.default_schema: infra_cicada_web 11 | datasource: 12 | max-active: 50 13 | initial-size: 32 14 | max-idle: 40 15 | min-idle: 1 16 | test-while-idle: true 17 | test-on-borrow: true 18 | validation-query: SELECT 1 19 | time-between-eviction-runs-millis: 5000 20 | min-evictable-idle-time-millis: 60000 21 | 22 | job.slot.range: 65536 23 | trace: 24 | log.root.dir: /opt/yrd_logs/tengine/cicada/ 25 | progress.file.path: /opt/yrd_data/cicada/progress.rcd 26 | 27 | --- 28 | spring: 29 | profiles: env_test 30 | datasource: 31 | platform: mysql 32 | url: jdbc:p6spy:mysql://127.0.0.1:3306/cicada?useUnicode=true&characterEncoding=UTF-8 33 | username: root 34 | password: 123456 35 | 36 | elasticsearch: 37 | cluster.name: cicada_warehouse 38 | bulk.await.minutes: 10 39 | node: 40 | addr: 127.0.0.1 41 | port: 9300 42 | index: 43 | type.name: details 44 | span.prefix: cicada-span 45 | annotation.prefix: cicada-annotation 46 | 47 | --- 48 | spring: 49 | profiles: env_development 50 | datasource: 51 | platform: mysql 52 | url: jdbc:p6spy:mysql://localhost:3306/cicada?useUnicode=true&characterEncoding=UTF-8 53 | username: cicada 54 | password: dev_cicada_passwd 55 | 56 | elasticsearch: 57 | cluster.name: cicada_warehouse 58 | bulk.await.minutes: 10 59 | node: 60 | addr: 127.0.0.1 61 | port: 9300 62 | index: 63 | type.name: details 64 | span.prefix: cicada-span 65 | annotation.prefix: cicada-annotation 66 | 67 | --- 68 | spring: 69 | profiles: env_production 70 | datasource: 71 | platform: mysql 72 | url: jdbc:p6spy:mysql://localhost:3306/cicada?useUnicode=true&characterEncoding=UTF-8 73 | username: cicada 74 | password: prod_cicada_passwd 75 | 76 | elasticsearch: 77 | cluster.name: cicada_warehouse 78 | bulk.await.minutes: 10 79 | node: 80 | addr: 127.0.0.1 81 | port: 9300 82 | index: 83 | type.name: details 84 | span.prefix: cicada-span 85 | annotation.prefix: cicada-annotation 86 | 87 | -------------------------------------------------------------------------------- /cicada-collector/src/main/resources/elastic/annotation.settings: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "number_of_shards": 5, 4 | "number_of_replicas": 1 5 | }, 6 | "mappings": { 7 | "details": { 8 | "dynamic": false, 9 | "include_in_all": false, 10 | "properties": { 11 | "traceId": {"type": "string", "index": "not_analyzed"}, 12 | "spanId": {"type": "string", "index": "not_analyzed"}, 13 | "type": {"type": "string", "index": "no"}, 14 | "key": {"type": "string", "index": "no"}, 15 | "value": {"type": "string", "index": "no"}, 16 | "timestamp": {"type": "long", "index": "no"}, 17 | "duration": {"type": "integer", "index": "no"}, 18 | "ip": {"type": "string", "index": "no"}, 19 | "port": {"type": "integer", "index": "no"} 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cicada-collector/src/main/resources/elastic/span.settings: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "number_of_shards": 5, 4 | "number_of_replicas": 1 5 | }, 6 | "mappings": { 7 | "details": { 8 | "dynamic": false, 9 | "include_in_all": false, 10 | "properties": { 11 | "appId": {"type": "integer", "index": "not_analyzed"}, 12 | "serviceId": {"type": "integer", "index": "not_analyzed"}, 13 | "methodId": {"type": "integer", "index": "not_analyzed"}, 14 | "traceId": {"type": "string", "index": "not_analyzed"}, 15 | "id": {"type": "string", "index": "not_analyzed"}, 16 | "parentId": {"type": "string", "index": "no"}, 17 | "startTime": {"type": "long", "index": "not_analyzed"}, 18 | "durationServer": {"type": "integer", "index": "not_analyzed"}, 19 | "hasException": {"type": "boolean", "index": "not_analyzed"}, 20 | "sliceNo": {"type": "integer", "index": "not_analyzed"} 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /cicada-collector/src/main/resources/elastic/trace.settings: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "number_of_shards": 5, 4 | "number_of_replicas": 1 5 | }, 6 | "mappings": { 7 | "details": { 8 | "dynamic": false, 9 | "include_in_all": false, 10 | "properties": { 11 | "appId": {"type": "integer", "index": "not_analyzed"}, 12 | "serviceId": {"type": "integer", "index": "not_analyzed"}, 13 | "methodId": {"type": "integer", "index": "not_analyzed"}, 14 | "id": {"type": "string", "index": "not_analyzed"}, 15 | "startTime": {"type": "long", "index": "no"}, 16 | "duration": {"type": "integer", "index": "no"}, 17 | "hasException": {"type": "boolean", "index": "not_analyzed"} 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /cicada-collector/src/main/resources/spy.properties: -------------------------------------------------------------------------------- 1 | driverlist=com.mysql.jdbc.Driver,org.h2.Driver 2 | appender=com.p6spy.engine.spy.appender.Slf4JLogger 3 | useprefix=false 4 | deregisterdrivers=true 5 | excludecategories=info,debug,result,resultset,batch,commit 6 | databaseDialectDateFormat=yyyy-MM-dd 7 | filter=true 8 | exclude=SELECT 1 9 | dateformat=yyyy-MM-dd HH:mm:ss:SS -------------------------------------------------------------------------------- /cicada-collector/src/test/java/com/yirendai/infra/cicada/CollectorTest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import org.springframework.boot.test.SpringApplicationConfiguration; 4 | import org.springframework.test.context.ActiveProfiles; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Inherited; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | 12 | @Inherited 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.TYPE) 15 | @SpringApplicationConfiguration(classes = {Application.class}) 16 | @ActiveProfiles("env_test") 17 | public @interface CollectorTest { 18 | } 19 | -------------------------------------------------------------------------------- /cicada-collector/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /cicada-common-trace/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 4.0.0 5 | 6 | com.yirendai.infra 7 | cicada 8 | 2.0.1 9 | 10 | cicada-common-trace 11 | 12 | 13 | 14 | org.projectlombok 15 | lombok 16 | 17 | 18 | com.alibaba 19 | fastjson 20 | 21 | 22 | org.slf4j 23 | slf4j-api 24 | 25 | 26 | 27 | 28 | 29 | release 30 | 31 | 32 | 33 | 34 | org.apache.maven.plugins 35 | maven-source-plugin 36 | 2.2.1 37 | 38 | 39 | package 40 | 41 | jar-no-fork 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-javadoc-plugin 50 | 2.9.1 51 | 52 | 53 | package 54 | 55 | jar 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-gpg-plugin 64 | 1.5 65 | 66 | 67 | verify 68 | 69 | sign 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | maven-central 79 | https://oss.sonatype.org/content/repositories/snapshots/ 80 | 81 | 82 | maven-central 83 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /cicada-common-trace/src/main/java/com/yirendai/infra/cicada/constants/AnnotationType.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.constants; 2 | 3 | public enum AnnotationType { 4 | CLIENT_SEND, CLIENT_RECEIVE, SERVER_SEND, SERVER_RECEIVE; 5 | } 6 | -------------------------------------------------------------------------------- /cicada-common-trace/src/main/java/com/yirendai/infra/cicada/constants/BinaryAnnotationType.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.constants; 2 | 3 | public enum BinaryAnnotationType { 4 | EVENT, EXCEPTION; 5 | } 6 | -------------------------------------------------------------------------------- /cicada-common-trace/src/main/java/com/yirendai/infra/cicada/entity/trace/Annotation.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity.trace; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | import com.yirendai.infra.cicada.constants.AnnotationType; 5 | 6 | import lombok.AllArgsConstructor; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import java.io.Serializable; 11 | 12 | @Data 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class Annotation implements Serializable { 16 | private static final long serialVersionUID = 5906564687914191864L; 17 | 18 | private long timestamp; 19 | private AnnotationType type; 20 | private String ip; 21 | private int port; 22 | private int duration; // 这是个没有意义的字段,主要用于清洗成AnnotationModel时可以getDuration 23 | 24 | public void setEndpoint(Endpoint endpoint) { 25 | if (endpoint == null) { 26 | return; 27 | } 28 | 29 | this.ip = endpoint.getIp(); 30 | this.port = endpoint.getPort(); 31 | } 32 | 33 | @JSONField(serialize = false) 34 | public Endpoint getEndpoint() { 35 | Endpoint endpoint = new Endpoint(); 36 | endpoint.setIp(ip); 37 | endpoint.setPort(port); 38 | return endpoint; 39 | } 40 | 41 | private boolean equals(String str1, String str2) { 42 | return (str1 != null ? str1.equals(str2) : str2 == null); 43 | } 44 | 45 | @Override 46 | public boolean equals(Object obj) { 47 | if (this == obj) { 48 | return true; 49 | } 50 | if (!(obj instanceof Annotation)) { 51 | return false; 52 | } 53 | 54 | Annotation that = (Annotation) obj; 55 | if (timestamp != that.timestamp) { 56 | return false; 57 | } 58 | 59 | if (type != that.type) { 60 | return false; 61 | } 62 | 63 | if (!this.equals(ip, that.ip)) { 64 | return false; 65 | } 66 | 67 | if (port != that.port) { 68 | return false; 69 | } 70 | 71 | return true; 72 | } 73 | 74 | @Override 75 | public int hashCode() { 76 | int result = 17; 77 | result = 31 * result + (int) (timestamp ^ (timestamp >>> 32)); 78 | result = 31 * result + (type != null ? type.hashCode() : 0); 79 | result = 31 * result + (ip != null ? ip.hashCode() : 0); 80 | result = 31 * result + port; 81 | return result; 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "Annotation{" + "timestamp=" + timestamp + ", type='" + type + '\'' + ", ip=" + ip + ", port=" + port + '}'; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /cicada-common-trace/src/main/java/com/yirendai/infra/cicada/entity/trace/BinaryAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity.trace; 2 | 3 | import com.yirendai.infra.cicada.constants.BinaryAnnotationType; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.io.Serializable; 10 | 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class BinaryAnnotation implements Serializable { 15 | private static final long serialVersionUID = -5829069208358509837L; 16 | 17 | private String key; 18 | private String value; 19 | private BinaryAnnotationType type = BinaryAnnotationType.EVENT; 20 | private long timestamp = System.currentTimeMillis(); 21 | private String ip; 22 | private int port; 23 | private int duration = 0; 24 | 25 | public void setThrowable(String className, String methodName, Throwable ex) { 26 | if (ex != null) { 27 | ex.printStackTrace(); 28 | setKey(className); 29 | setValue(methodName + "," + ex.toString()); 30 | setType(BinaryAnnotationType.EXCEPTION); 31 | } 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "BinaryAnnotation{" + "key='" + key + '\'' + ", value=" + value + ", type='" + type + '\'' + ", timestamp=" 37 | + timestamp + ", ip=" + ip + ", port=" + port + '}'; 38 | } 39 | 40 | public void setEndpoint(Endpoint endpoint) { 41 | if (endpoint == null) { 42 | return; 43 | } 44 | 45 | this.ip = endpoint.getIp(); 46 | this.port = endpoint.getPort(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /cicada-common-trace/src/main/java/com/yirendai/infra/cicada/entity/trace/Endpoint.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity.trace; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class Endpoint implements Serializable { 13 | private static final long serialVersionUID = -1819879293130044091L; 14 | private String ip; 15 | private int port; 16 | 17 | @Override 18 | public String toString() { 19 | return "Endpoint{" + "ip='" + ip + '\'' + ", port=" + port + '}'; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object obj) { 24 | if (this == obj) { 25 | return true; 26 | } 27 | if (!(obj instanceof Endpoint)) { 28 | return false; 29 | } 30 | 31 | Endpoint endpoint = (Endpoint) obj; 32 | if (!ip.equals(endpoint.ip)) { 33 | return false; 34 | } 35 | if (port != endpoint.port) { 36 | return false; 37 | } 38 | 39 | return true; 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | int result = 17; 45 | result = 31 * result + (ip != null ? ip.hashCode() : 0); 46 | result = 31 * result + port; 47 | return result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cicada-common-trace/src/main/java/com/yirendai/infra/cicada/utils/IpUtils.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.utils; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.net.InetAddress; 8 | import java.net.NetworkInterface; 9 | import java.net.SocketException; 10 | import java.util.Enumeration; 11 | 12 | public class IpUtils { 13 | 14 | private static final Logger LOG = LoggerFactory.getLogger(IpUtils.class); 15 | 16 | /** 17 | * 静态变量缓存IP. 18 | */ 19 | private static String cachedip = null; 20 | 21 | /* 22 | * 同步块使用 23 | */ 24 | private static Object syncObject = new Object(); 25 | 26 | static { 27 | try { 28 | cachedip = getRealIp(); 29 | } catch (SocketException ex) { 30 | LOG.error("", ex); 31 | cachedip = "127.0.0.1"; 32 | } 33 | } 34 | 35 | /** 36 | * 取得本机的IP,并把结果放到static变量中. 37 | * 38 | * @return 如果有多个IP地址返回外网的IP,多个外网IP返回第一个IP(在多网管等特殊情况下) 39 | * @throws SocketException 40 | */ 41 | public static String getRealIpWithStaticCache() { 42 | if (cachedip == null) { 43 | synchronized (syncObject) { 44 | try { 45 | cachedip = getRealIp(); 46 | } catch (SocketException ex) { 47 | LOG.error("", ex); 48 | cachedip = "127.0.0.1"; 49 | } 50 | } 51 | return cachedip; 52 | } else { 53 | return cachedip; 54 | } 55 | } 56 | 57 | /** 58 | * 刷新getRealIpWithStaticCache()方法的static变量. 59 | */ 60 | public static void flushIpStaticCache() { 61 | synchronized (syncObject) { 62 | cachedip = null; 63 | } 64 | } 65 | 66 | /** 67 | * 取得本机的IP. 68 | * 69 | * @return 如果有多个IP地址返回外网的IP,多个外网IP返回第一个IP(在多网管等特殊情况下) 70 | * @throws SocketException 71 | */ 72 | public static String getRealIp() throws SocketException { 73 | String localip = null; // 本地IP,如果没有配置外网IP则返回它 74 | String netip = null; // 外网IP 75 | 76 | Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces(); 77 | InetAddress ip = null; 78 | boolean finded = false; // 是否找到外网IP 79 | while (netInterfaces.hasMoreElements() && !finded) { 80 | NetworkInterface ni = netInterfaces.nextElement(); 81 | Enumeration address = ni.getInetAddresses(); 82 | while (address.hasMoreElements()) { 83 | ip = address.nextElement(); 84 | if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() 85 | && ip.getHostAddress().indexOf(":") == -1) { // 外网IP 86 | netip = ip.getHostAddress(); 87 | finded = true; 88 | break; 89 | } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() 90 | && ip.getHostAddress().indexOf(":") == -1) { // 内网IP 91 | localip = ip.getHostAddress(); 92 | } 93 | } 94 | } 95 | if (netip != null && !"".equals(netip)) { 96 | return netip; 97 | } else { 98 | return localip; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /cicada-common-trace/src/test/java/com/yirendai/infra/cicada/SpanTest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import com.yirendai.infra.cicada.entity.trace.Span; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | public class SpanTest { 10 | public static void main(String[] args) { 11 | List list = new ArrayList(); 12 | 13 | Span span2 = new Span(); 14 | span2.setTraceId("1"); 15 | span2.setId("1.1"); 16 | list.add(span2); 17 | 18 | Span span4 = new Span(); 19 | span4.setTraceId("1"); 20 | span4.setId("1.1.1"); 21 | list.add(span4); 22 | 23 | Span span3 = new Span(); 24 | span3.setTraceId("1"); 25 | span3.setId("1.13"); 26 | list.add(span3); 27 | 28 | Span span1 = new Span(); 29 | span1.setTraceId("1"); 30 | span1.setId("1"); 31 | list.add(span1); 32 | 33 | Collections.sort(list); 34 | 35 | for (Span span : list) { 36 | System.err.println("span:" + span); 37 | } 38 | 39 | System.err.println("=============================\n"); 40 | 41 | span1.setTraceId("1.2"); 42 | span2.setTraceId("1.1"); 43 | span3.setTraceId("1.1.13"); 44 | span4.setTraceId("1.1.1"); 45 | Collections.sort(list); 46 | 47 | for (Span span : list) { 48 | System.err.println("span:" + span); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cicada-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.yirendai.infra 8 | cicada 9 | 2.0.1 10 | 11 | cicada-common 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | com.yirendai.infra 20 | cicada-common-trace 21 | 22 | 23 | javax.el 24 | javax.el-api 25 | 26 | 27 | org.elasticsearch 28 | elasticsearch 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | 34 | 35 | com.fasterxml.jackson.core 36 | jackson-databind 37 | 38 | 39 | joda-time 40 | joda-time 41 | 42 | 43 | com.fasterxml.jackson.datatype 44 | jackson-datatype-joda 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-data-jpa 53 | 54 | 55 | mysql 56 | mysql-connector-java 57 | 58 | 59 | com.h2database 60 | h2 61 | 62 | 63 | p6spy 64 | p6spy 65 | 66 | 67 | org.hibernate 68 | hibernate-validator 69 | 70 | 71 | org.apache.commons 72 | commons-lang3 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/configure/ElasticSearchConfigure.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.configure; 2 | 3 | import lombok.SneakyThrows; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import org.elasticsearch.client.transport.TransportClient; 7 | import org.elasticsearch.common.settings.Settings; 8 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | import java.net.InetAddress; 14 | import java.net.UnknownHostException; 15 | 16 | @Slf4j 17 | @Configuration 18 | public class ElasticSearchConfigure { 19 | @Value("${elasticsearch.node.addr}") 20 | private String nodeAddr; 21 | 22 | @Value("${elasticsearch.node.port}") 23 | private int nodePort; 24 | 25 | @Value("${elasticsearch.cluster.name}") 26 | private String clusterName; 27 | 28 | @Bean 29 | public TransportClient client() { 30 | TransportClient client = null; 31 | try { 32 | client = TransportClient.builder().settings(this.settings()).build() // 33 | .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(nodeAddr), nodePort)); 34 | } catch (UnknownHostException ex) { 35 | log.error("init es client host:{},port:{} error", nodeAddr, nodePort, ex); 36 | } 37 | return client; 38 | } 39 | 40 | @SneakyThrows 41 | public Settings settings() { 42 | return Settings.settingsBuilder() // 43 | .put("cluster.name", clusterName) // 44 | .put("client.transport.sniff", true) // 45 | .build(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/constants/DateTimeFormats.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.constants; 2 | 3 | import org.joda.time.format.DateTimeFormat; 4 | import org.joda.time.format.DateTimeFormatter; 5 | 6 | public class DateTimeFormats { 7 | 8 | public static final String FULL_DATE_CHINESE = "yyyy年MM月dd日"; 9 | public static final DateTimeFormatter FULL_DATE_CHINESE_FORMATTER = 10 | DateTimeFormat.forPattern(DateTimeFormats.FULL_DATE_CHINESE); 11 | 12 | public static final String HALF_DATE_CHINESE = "MM月dd日"; 13 | public static final DateTimeFormatter HALF_DATE_CHINESE_FORMATTER = 14 | DateTimeFormat.forPattern(DateTimeFormats.HALF_DATE_CHINESE); 15 | 16 | public static final String FULL_DATE_ENGLISH = "yyyy-MM-dd"; 17 | public static final DateTimeFormatter FULL_DATE_ENGLISH_FORMATTER = 18 | DateTimeFormat.forPattern(DateTimeFormats.FULL_DATE_ENGLISH); 19 | 20 | public static final String FULL_TIME_ENGLISH = "yyyy-MM-dd HH:mm:ss"; 21 | public static final DateTimeFormatter FULL_TIME_ENGLISH_FORMATTER = 22 | DateTimeFormat.forPattern(DateTimeFormats.FULL_TIME_ENGLISH); 23 | 24 | public static final String FULL_TIME_COMPACT_ENGLISH = "yyyyMMddHHmmss"; 25 | public static final DateTimeFormatter FULL_TIME_COMPACT_ENGLISH_FORMATTER = 26 | DateTimeFormat.forPattern(DateTimeFormats.FULL_TIME_COMPACT_ENGLISH); 27 | 28 | public static final String CHINESE_TIME_ZONE = "GMT+8"; 29 | } 30 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/entity/AppInfo.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.fasterxml.jackson.annotation.JsonFormat; 5 | import com.fasterxml.jackson.annotation.JsonIgnore; 6 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 7 | import com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer; 8 | import com.yirendai.infra.cicada.constants.DateTimeFormats; 9 | 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | 13 | import org.joda.time.DateTime; 14 | import org.springframework.data.annotation.CreatedDate; 15 | 16 | import java.util.List; 17 | 18 | import javax.persistence.CascadeType; 19 | import javax.persistence.Entity; 20 | import javax.persistence.GeneratedValue; 21 | import javax.persistence.GenerationType; 22 | import javax.persistence.Id; 23 | import javax.persistence.OneToMany; 24 | import javax.persistence.Table; 25 | 26 | @Data 27 | @NoArgsConstructor 28 | @Entity 29 | @Table(name = "app_info") 30 | public class AppInfo { 31 | @Id 32 | @GeneratedValue(strategy = GenerationType.AUTO) 33 | private Integer id; 34 | 35 | private String appName; 36 | 37 | @OneToMany(targetEntity = ServiceInfo.class, // 38 | cascade = CascadeType.REMOVE, // 39 | mappedBy = "appId", orphanRemoval = true) 40 | @JsonIgnore 41 | private List services; 42 | 43 | @JsonFormat(shape = JsonFormat.Shape.STRING, // 44 | pattern = DateTimeFormats.FULL_TIME_ENGLISH, // 45 | timezone = DateTimeFormats.CHINESE_TIME_ZONE) 46 | @JsonSerialize(using = DateTimeSerializer.class) 47 | @CreatedDate 48 | DateTime registerTime = DateTime.now(); 49 | 50 | @Override 51 | public String toString() { 52 | return JSON.toJSONString(this); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/entity/CollectEntity.java: -------------------------------------------------------------------------------- 1 | /*************************************************************** 2 | * 3 | * Copyright (c) 2016 yirendai.com, Inc. All Rights Reserved 4 | * 5 | ***************************************************************/ 6 | 7 | /** 8 | * @file CollectEntity.java 9 | * @author melody(zechengzhao@yirendai.com) 10 | * @date 2016年4月6日 11 | * @brief collector端与统计端传输的数据结构 12 | */ 13 | 14 | package com.yirendai.infra.cicada.entity; 15 | 16 | import com.yirendai.infra.cicada.entity.model.SpanModel; 17 | 18 | import lombok.AllArgsConstructor; 19 | import lombok.Data; 20 | import lombok.NoArgsConstructor; 21 | 22 | import java.util.List; 23 | 24 | @Data 25 | @NoArgsConstructor 26 | @AllArgsConstructor 27 | public class CollectEntity { 28 | public List spans; 29 | } 30 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/entity/MethodInfo.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer; 6 | import com.yirendai.infra.cicada.constants.DateTimeFormats; 7 | 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | import org.joda.time.DateTime; 12 | import org.springframework.data.annotation.CreatedDate; 13 | 14 | import javax.persistence.Entity; 15 | import javax.persistence.GeneratedValue; 16 | import javax.persistence.GenerationType; 17 | import javax.persistence.Id; 18 | import javax.persistence.Table; 19 | 20 | @Data 21 | @NoArgsConstructor 22 | @Entity 23 | @Table(name = "method_info") 24 | public class MethodInfo { 25 | @Id 26 | @GeneratedValue(strategy = GenerationType.AUTO) 27 | private Integer id; 28 | 29 | private int serviceId; 30 | private String methodName; 31 | 32 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeFormats.FULL_TIME_ENGLISH, 33 | timezone = DateTimeFormats.CHINESE_TIME_ZONE) 34 | @JsonSerialize(using = DateTimeSerializer.class) 35 | @CreatedDate 36 | DateTime registerTime = DateTime.now(); 37 | } 38 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/entity/ServiceInfo.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 6 | import com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer; 7 | import com.yirendai.infra.cicada.constants.DateTimeFormats; 8 | 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | 12 | import org.joda.time.DateTime; 13 | import org.springframework.data.annotation.CreatedDate; 14 | 15 | import java.util.List; 16 | 17 | import javax.persistence.CascadeType; 18 | import javax.persistence.Entity; 19 | import javax.persistence.GeneratedValue; 20 | import javax.persistence.GenerationType; 21 | import javax.persistence.Id; 22 | import javax.persistence.OneToMany; 23 | import javax.persistence.Table; 24 | 25 | @Data 26 | @NoArgsConstructor 27 | @Entity 28 | @Table(name = "service_info") 29 | public class ServiceInfo { 30 | @Id 31 | @GeneratedValue(strategy = GenerationType.AUTO) 32 | private Integer id; 33 | 34 | private Integer appId; 35 | private String serviceName; 36 | 37 | @OneToMany(targetEntity = MethodInfo.class, cascade = CascadeType.REMOVE, mappedBy = "serviceId", 38 | orphanRemoval = true) 39 | @JsonIgnore 40 | private List methods; 41 | 42 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeFormats.FULL_TIME_ENGLISH, 43 | timezone = DateTimeFormats.CHINESE_TIME_ZONE) 44 | @JsonSerialize(using = DateTimeSerializer.class) 45 | @CreatedDate 46 | DateTime registerTime = DateTime.now(); 47 | } 48 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/entity/SpanEntity.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import com.yirendai.infra.cicada.entity.model.AnnotationModel; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | 8 | import java.io.Serializable; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | public class SpanEntity implements Serializable, Comparable { 15 | private static final long serialVersionUID = -527884689646021836L; 16 | 17 | private String traceId; 18 | private String id; 19 | private String parentId; 20 | 21 | private String appName; 22 | private String serviceName; 23 | private String methodName; 24 | 25 | private int durationServer; 26 | private int durationClient; 27 | 28 | private boolean hasException; 29 | private List annotations; 30 | 31 | public SpanEntity() { 32 | this.hasException = false; 33 | this.annotations = new LinkedList(); 34 | } 35 | 36 | public int compareTo(final SpanEntity other) { 37 | final String[] thisSpanArr = id.split("\\."); 38 | final String[] otherSpanArr = other.id.split("\\."); 39 | 40 | int shortLength = thisSpanArr.length; 41 | if (thisSpanArr.length > otherSpanArr.length) { 42 | shortLength = otherSpanArr.length; 43 | if (this.id.startsWith(other.id)) { 44 | return 1; 45 | } 46 | } else if (thisSpanArr.length < otherSpanArr.length) { 47 | if (other.id.startsWith(this.id)) { 48 | return -1; 49 | } 50 | } 51 | 52 | for (int i = 0; i < shortLength; i++) { 53 | final String thisA = thisSpanArr[i]; 54 | final String otherA = otherSpanArr[i]; 55 | 56 | if (!thisA.equals(otherA)) { 57 | return (Integer.parseInt(thisA) - Integer.parseInt(otherA)); 58 | } 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | int result = 17; 67 | result = result * 31 + id.hashCode(); 68 | return result; 69 | } 70 | 71 | @Override 72 | public boolean equals(final Object obj) { 73 | final boolean equals; 74 | if (this == obj) { 75 | equals = true; 76 | } else { 77 | if (!(obj instanceof SpanEntity)) { 78 | equals = false; 79 | } else { 80 | final SpanEntity that = (SpanEntity) obj; 81 | equals = traceId.equals(that.traceId) && id.equals(that.id); 82 | } 83 | } 84 | 85 | return equals; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/entity/model/AnnotationModel.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 清洗后的Annotation和BinaryAnnotation数据存储模型. 9 | * @author Zecheng 10 | */ 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class AnnotationModel { 15 | private String traceId; 16 | private String spanId; 17 | 18 | private String key; 19 | private String value; 20 | private String type; 21 | private long timestamp; 22 | private int duration; 23 | private String ip; 24 | private int port; 25 | } 26 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/entity/model/SpanModel.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity.model; 2 | 3 | import com.alibaba.fastjson.annotation.JSONField; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | 8 | import java.io.Serializable; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | public class SpanModel implements Serializable, Comparable { 13 | 14 | private static final long serialVersionUID = 6055130304371692968L; 15 | 16 | private String traceId; 17 | private String id; 18 | private String parentId; 19 | 20 | private int appId; 21 | private int serviceId; 22 | private int methodId; 23 | 24 | private long startTime; 25 | private int durationServer; 26 | private boolean hasException; 27 | 28 | // 用于分布式计算,任务分片 29 | private int sliceNo; 30 | 31 | public SpanModel() { 32 | this.hasException = false; 33 | this.sliceNo = 0; 34 | } 35 | 36 | @JSONField(serialize = false) 37 | public boolean isRootSpan() { 38 | return parentId == null; 39 | } 40 | 41 | public int compareTo(final SpanModel other) { 42 | final String[] thisSpanArr = id.split("\\."); 43 | final String[] otherSpanArr = other.id.split("\\."); 44 | 45 | int shortLength = thisSpanArr.length; 46 | if (thisSpanArr.length > otherSpanArr.length) { 47 | shortLength = otherSpanArr.length; 48 | if (this.id.startsWith(other.id)) { 49 | return 1; 50 | } 51 | } else if (thisSpanArr.length < otherSpanArr.length) { 52 | if (other.id.startsWith(this.id)) { 53 | return -1; 54 | } 55 | } 56 | 57 | for (int i = 0; i < shortLength; i++) { 58 | final String thisA = thisSpanArr[i]; 59 | final String otherA = otherSpanArr[i]; 60 | 61 | if (!thisA.equals(otherA)) { 62 | return (Integer.parseInt(thisA) - Integer.parseInt(otherA)); 63 | } 64 | } 65 | 66 | return 0; 67 | } 68 | 69 | public void calcSliceNo(final int range) { 70 | sliceNo = 17; 71 | sliceNo = sliceNo * 31 + appId; 72 | sliceNo = sliceNo * 31 + serviceId; 73 | sliceNo = sliceNo * 31 + methodId; 74 | 75 | sliceNo = Math.abs(sliceNo % range); 76 | } 77 | 78 | @Override 79 | public int hashCode() { 80 | int result = 17; 81 | result = result * 31 + id.hashCode(); 82 | return result; 83 | } 84 | 85 | @Override 86 | public boolean equals(final Object obj) { 87 | final boolean equals; 88 | if (this == obj) { 89 | equals = true; 90 | } else { 91 | if (!(obj instanceof SpanModel)) { 92 | equals = false; 93 | } else { 94 | final SpanModel that = (SpanModel) obj; 95 | equals = traceId.equals(that.traceId) && id.equals(that.id); 96 | } 97 | } 98 | 99 | return equals; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/repository/AppRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.yirendai.infra.cicada.entity.AppInfo; 4 | 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Query; 9 | 10 | public interface AppRepository extends JpaRepository { 11 | 12 | @Query 13 | AppInfo findByAppName(String appName); 14 | 15 | @Query 16 | Page findByAppNameLike(String appName,Pageable pageable); 17 | } 18 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/repository/MethodRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.yirendai.infra.cicada.entity.MethodInfo; 4 | 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Query; 9 | 10 | import javax.transaction.Transactional; 11 | 12 | @Transactional 13 | public interface MethodRepository extends JpaRepository { 14 | 15 | @Query 16 | MethodInfo findByServiceIdAndMethodName(int serviceId, String methodName); 17 | 18 | @Query 19 | Page findByServiceId(int serviceId,Pageable pageable); 20 | 21 | @Query 22 | Page findByServiceIdAndMethodNameLike(int serviceId,String methodName,Pageable pageable); 23 | 24 | @Query 25 | Page findByMethodNameLike(String methodName,Pageable pageable); 26 | } 27 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/repository/ServiceRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.yirendai.infra.cicada.entity.ServiceInfo; 4 | 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Query; 9 | 10 | import javax.transaction.Transactional; 11 | 12 | @Transactional 13 | public interface ServiceRepository extends JpaRepository { 14 | 15 | @Query 16 | ServiceInfo findByAppIdAndServiceName(int appId, String serviceName); 17 | 18 | @Query 19 | Page findByAppId(int appId,Pageable pageable); 20 | 21 | @Query 22 | Page findByAppIdAndServiceNameLike(int appId, String serviceName,Pageable pageable); 23 | 24 | @Query 25 | Page findByServiceNameLike(String serviceName,Pageable pageable); 26 | } 27 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/resource/RegisterInfoResource.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.resource; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class RegisterInfoResource { 11 | private String appName; 12 | private String serviceName; 13 | private String methodName; 14 | } 15 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/service/AppService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.service; 2 | 3 | import com.yirendai.infra.cicada.entity.AppInfo; 4 | import com.yirendai.infra.cicada.repository.AppRepository; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.domain.Pageable; 10 | import org.springframework.stereotype.Component; 11 | 12 | import javax.transaction.Transactional; 13 | 14 | @Component 15 | @Transactional 16 | public class AppService { 17 | @Autowired 18 | AppRepository repo; 19 | 20 | public int getAppId(final String appName) { 21 | AppInfo appInfo = repo.findByAppName(appName); 22 | if (appInfo == null) { 23 | appInfo = new AppInfo(); 24 | appInfo.setAppName(appName); 25 | 26 | repo.save(appInfo); 27 | } 28 | 29 | return appInfo.getId(); 30 | } 31 | 32 | public Page fetchAppInfos(final Pageable pageable) { 33 | return repo.findAll(pageable); 34 | } 35 | 36 | public Page findByAppNameLike(final String appName, final Pageable pageable) { 37 | final Page appInfoPage; 38 | if (StringUtils.isEmpty(appName)) { 39 | appInfoPage = repo.findAll(pageable); 40 | } else { 41 | final String fuzzyAppName = new StringBuilder().append("%").append(appName).append("%").toString(); 42 | appInfoPage = repo.findByAppNameLike(fuzzyAppName, pageable); 43 | } 44 | 45 | return appInfoPage; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cicada-common/src/main/java/com/yirendai/infra/cicada/service/ServiceService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.service; 2 | 3 | import com.yirendai.infra.cicada.entity.ServiceInfo; 4 | import com.yirendai.infra.cicada.repository.ServiceRepository; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.domain.Page; 9 | import org.springframework.data.domain.Pageable; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | import javax.transaction.Transactional; 16 | 17 | @Service 18 | @Transactional 19 | public class ServiceService { 20 | 21 | @Autowired 22 | private AppService appService; 23 | 24 | @Autowired 25 | private ServiceRepository serviceRepo; 26 | 27 | public int getServiceId(final String appName, final String serviceName) { 28 | final int appId = appService.getAppId(appName); 29 | ServiceInfo service = serviceRepo.findByAppIdAndServiceName(appId, serviceName); 30 | if (service == null) { 31 | service = new ServiceInfo(); 32 | service.setAppId(appId); 33 | service.setServiceName(serviceName); 34 | serviceRepo.save(service); 35 | } 36 | 37 | return service.getId(); 38 | } 39 | 40 | public Map getServiceIdMap(final String appName, final String serviceName) { 41 | final Map map = new HashMap(); 42 | final int appId = appService.getAppId(appName); 43 | map.put("appId", appId); 44 | 45 | ServiceInfo service = serviceRepo.findByAppIdAndServiceName(appId, serviceName); 46 | if (service == null) { 47 | service = new ServiceInfo(); 48 | service.setAppId(appId); 49 | service.setServiceName(serviceName); 50 | serviceRepo.save(service); 51 | } 52 | 53 | map.put("serviceId", service.getId()); 54 | return map; 55 | } 56 | 57 | public ServiceInfo getServiceInfo(final int serviceId) { 58 | return serviceRepo.findOne(serviceId); 59 | } 60 | 61 | public Page getServicesByAppId(final int appId, final Pageable pageable) { 62 | return serviceRepo.findByAppId(appId, pageable); 63 | } 64 | 65 | public Page findByAppIdAndserviceNameLike(final int appId, // 66 | final String serviceName, // 67 | final Pageable pageable) { 68 | final Page pageResult; 69 | if (StringUtils.isEmpty(serviceName)) { 70 | pageResult = serviceRepo.findByAppId(appId, pageable); 71 | } else { 72 | final String fuzzyServiceName = new StringBuilder().append("%").append(serviceName).append("%").toString(); 73 | pageResult = serviceRepo.findByAppIdAndServiceNameLike(appId, fuzzyServiceName, pageable); 74 | } 75 | 76 | return pageResult; 77 | } 78 | 79 | public Page findByServiceNameLike(final String serviceName, final Pageable pageable) { 80 | return serviceRepo.findByServiceNameLike(serviceName, pageable); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-consumer-web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.yirendai.infra 8 | cicada-demo 9 | 2.0.1 10 | 11 | cicada-demo-consumer-web 12 | cicada-demo-consumer-web 13 | http://maven.apache.org 14 | 15 | UTF-8 16 | 17 | 18 | 19 | 20 | junit 21 | junit 22 | test 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | com.yirendai.infra 30 | cicada-demo-provider-api 31 | 32 | 33 | org.aspectj 34 | aspectjweaver 35 | 36 | 37 | com.yirendai.infra 38 | cicada-client 39 | aspectj 40 | 41 | 42 | com.alibaba 43 | dubbo 44 | 45 | 46 | org.projectlombok 47 | lombok 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | org.codehaus.mojo 59 | aspectj-maven-plugin 60 | 1.8 61 | 62 | 63 | 64 | compile 65 | test-compile 66 | 67 | 68 | 69 | 1.7 70 | 1.7 71 | 1.7 72 | 73 | 74 | com.yirendai.infra 75 | cicada-client 76 | aspectj 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-consumer-web/src/main/java/com/yirendai/infra/cicada/demo/consumer/web/ConsumerController.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.consumer.web; 2 | 3 | import com.yirendai.infra.cicada.demo.provider.api.DemoService; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.boot.web.servlet.ServletComponentScan; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.io.UnsupportedEncodingException; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | @RestController 18 | @SpringBootApplication(scanBasePackages={"com.yirendai.infra.cicada"}) 19 | @ServletComponentScan(basePackages={"com.yirendai.infra.cicada"}) 20 | public class ConsumerController { 21 | 22 | @Autowired 23 | private DemoService demoService; 24 | 25 | @RequestMapping("/hi") 26 | String home() { 27 | return "Hello World!"; 28 | } 29 | 30 | @RequestMapping(value = "/testAction", method = RequestMethod.GET) 31 | @ResponseBody 32 | public String allOnActivities() throws UnsupportedEncodingException { 33 | asleepMethod(); 34 | String helloStr = demoService.sayHello("testAction"); 35 | return helloStr; 36 | } 37 | 38 | @RequestMapping(value = "/test", method = RequestMethod.GET) 39 | @ResponseBody 40 | public String test() throws UnsupportedEncodingException { 41 | asleepMethod(); 42 | String helloStr = demoService.sayHello("test"); 43 | return helloStr; 44 | } 45 | 46 | @RequestMapping(value = "/testException", method = RequestMethod.GET) 47 | @ResponseBody 48 | public String testException() throws UnsupportedEncodingException { 49 | asleepMethod(); 50 | demoService.testException("myException"); 51 | return "succ"; 52 | } 53 | 54 | private void asleepMethod() { 55 | try { 56 | TimeUnit.MILLISECONDS.sleep(50); 57 | } catch (InterruptedException ex) { 58 | ; 59 | } 60 | } 61 | 62 | public static void main(String[] args) throws Exception { 63 | SpringApplication.run(ConsumerController.class, args); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-consumer-web/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | ###########dubbo配置开始################## 2 | dubbo.config: 3 | enabled: true 4 | 5 | applicationName: demo-consumer 6 | #localhost:2182,127.0.0.1:2181 逗号分隔 7 | zkUrls: 127.0.0.1:2181 8 | 9 | 10 | 11 | ############dubbo配置结束################# 12 | 13 | user: 14 | name: goodman 15 | 16 | cicada: 17 | url: http://localhost:9080/upload 18 | sampleRate: 100 19 | connectTimeout: 100 20 | soTimeout: 100 21 | batchSize: 32 22 | bufferSize: 1024 23 | tpsLimit: 2048 -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-consumer-web/src/test/java/com/yirendai/infra/cicada/demo/consumer/web/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.consumer.web; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.yirendai.infra 8 | cicada-demo 9 | 2.0.1 10 | 11 | cicada-demo-provider-api 12 | cicada-demo-provider-api 13 | http://maven.apache.org 14 | 15 | UTF-8 16 | 17 | 18 | 19 | junit 20 | junit 21 | test 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider-api/src/main/java/com/yirendai/infra/cicada/demo/provider/api/DemoService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.provider.api; 2 | 3 | public interface DemoService { 4 | String sayHello(String name); 5 | 6 | void testResult(String name); 7 | 8 | void testException(String arg); 9 | } 10 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider-api/src/test/java/com/yirendai/infra/cicada/demo/provider/api/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.provider.api; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.yirendai.infra 8 | cicada-demo 9 | 2.0.1 10 | 11 | cicada-demo-provider 12 | cicada-demo-provider 13 | http://maven.apache.org 14 | 15 | UTF-8 16 | 17 | 18 | 19 | 20 | junit 21 | junit 22 | test 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter 27 | 28 | 29 | com.yirendai.infra 30 | cicada-demo-provider-api 31 | 32 | 33 | org.aspectj 34 | aspectjweaver 35 | 36 | 37 | com.yirendai.infra 38 | cicada-client 39 | aspectj 40 | 41 | 42 | com.alibaba 43 | dubbo 44 | 45 | 46 | org.projectlombok 47 | lombok 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | org.codehaus.mojo 59 | aspectj-maven-plugin 60 | 1.8 61 | 62 | 63 | 64 | compile 65 | test-compile 66 | 67 | 68 | 69 | 1.7 70 | 1.7 71 | 1.7 72 | 73 | 74 | com.yirendai.infra 75 | cicada-client 76 | aspectj 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider/src/main/java/com/yirendai/infra/cicada/demo/provider/Provider.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.provider; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication(scanBasePackages={"com.yirendai.infra.cicada"}) 7 | public class Provider { 8 | // private static final Logger LOG = LoggerFactory.getLogger(Provider.class); 9 | 10 | // @RequestMapping("/h2") 11 | // String home() { 12 | // return "Hello World!"; 13 | // } 14 | // 15 | public static void main(String[] args) throws Exception { 16 | SpringApplication.run(Provider.class, args); 17 | 18 | /// System.in.read(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider/src/main/java/com/yirendai/infra/cicada/demo/provider/service/DemoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.provider.service; 2 | 3 | import com.yirendai.infra.cicada.capture.Traceable; 4 | import com.yirendai.infra.cicada.demo.provider.api.DemoService; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.concurrent.TimeUnit; 12 | 13 | @Service("demoService") 14 | public class DemoServiceImpl implements DemoService { 15 | private static final Logger LOGGER = LoggerFactory.getLogger(DemoServiceImpl.class); 16 | 17 | @Autowired 18 | private User user; 19 | 20 | public String sayHello(String name) { 21 | System.err.println("hhhe:" + name); 22 | // anotherMethod(); 23 | user.say(3); 24 | return "Hello " + name; 25 | } 26 | 27 | public void testResult(String name) { 28 | anotherMethod(); 29 | } 30 | 31 | @Override 32 | public void testException(String arg) { 33 | int aa = 1; 34 | int bb = 0; 35 | anotherMethod(); 36 | LOGGER.info("a/b=" + (aa / bb)); 37 | } 38 | 39 | @Traceable 40 | public void anotherMethod() { 41 | try { 42 | TimeUnit.MILLISECONDS.sleep(50); 43 | } catch (InterruptedException ex) { 44 | ; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider/src/main/java/com/yirendai/infra/cicada/demo/provider/service/User.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.provider.service; 2 | 3 | import com.yirendai.infra.cicada.capture.Traceable; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | @ConfigurationProperties(prefix = "demo.user", ignoreUnknownFields = true) 12 | public class User { 13 | private static final Logger LOGGER = LoggerFactory.getLogger(User.class); 14 | 15 | private String name = "test"; 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public void setName(String name) { 22 | this.name = name; 23 | } 24 | 25 | @Traceable 26 | public void say(int num) { 27 | LOGGER.info("hi, boy:the num is:" + num); 28 | 29 | num--; 30 | 31 | if (num > 0) { 32 | say(num); 33 | } 34 | } 35 | 36 | @Traceable 37 | public String toString() { 38 | return name; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | ###########dubbo配置开始################## 2 | dubbo.config: 3 | enabled: true 4 | 5 | applicationName: demo-provider 6 | #localhost:2182,127.0.0.1:2181 逗号分隔 7 | zkUrls: 127.0.0.1:2181 8 | protocolName: dubbo 9 | protocolPort: 20880 10 | providerProtocol: dubbo 11 | providerRetries: 0 12 | providerActives: 30 13 | providerAccepts: 1000 14 | providerTimeout: 750000 15 | providerToken: 333333 16 | 17 | ############dubbo配置结束################# 18 | 19 | demo.user: 20 | name: goodman 21 | 22 | cicada: 23 | url: http://localhost:9080/upload 24 | sampleRate: 100 25 | connectTimeout: 100 26 | soTimeout: 100 27 | batchSize: 32 28 | bufferSize: 1024 29 | tpsLimit: 2048 -------------------------------------------------------------------------------- /cicada-demo/cicada-demo-provider/src/test/java/com/yirendai/infra/cicada/demo/provider/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.demo.provider; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cicada-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.yirendai.infra 7 | cicada 8 | 2.0.1 9 | 10 | cicada-demo 11 | pom 12 | 13 | cicada-demo-provider-api 14 | cicada-demo-provider 15 | cicada-demo-consumer-web 16 | 17 | 18 | 19 | UTF-8 20 | 2.0.1 21 | 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-dependencies 29 | 1.3.6.RELEASE 30 | pom 31 | import 32 | 33 | 34 | 35 | com.yirendai.infra 36 | cicada-demo-provider-api 37 | ${project.version} 38 | 39 | 40 | com.yirendai.infra 41 | cicada-client 42 | aspectj 43 | ${cicada.version} 44 | 45 | 46 | 47 | 48 | 49 | 50 | com.github.sgroschupf 51 | zkclient 52 | 53 | 54 | log4j 55 | log4j 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /cicada-docs/cicada-client-performance.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | # 客户端性能说明文档 4 | 5 | ## 概要 6 | 本文档主要阐述Cicada客户端性能相关的问题 7 | 8 | ## FAQ & 解决方案 9 | ### 1、采用何种方案减少对应用程序的影响? 10 | cicada客户端主要涉及到两个功能:一个是日志收集功能,一个是将收集好的日志发送到远程服务器的功能。前者通常耗时较少,且没太大优化空间;后者涉及到IO,处理较慢,性能优化主要针对后者。 11 | **最终方案:批处理+异步发送。** 12 | 13 | ### 2、都采用了那些措施增加日志吞吐量? 14 | 一、批处理 15 | 二、用高性能、低延迟的消息处理框架Disruptor替换BlockingQueue作为线程间传递消息的框架,提升消息处理效率; 16 | 17 | ### 3、日志传送过程中由于第三方原因(日志收集服务器挂掉、网络异常等)导致消息处理速度过慢,消息堆积可能导致内存溢出,如何处理? 18 | 增加了连接超时设置和传输超时设置,超过一定时长的日志直接扔掉 19 | 20 | ### 4、对于各种原因(如程序异常)导致的单位时间内抓取的日志量过多的情况,如何处理? 21 | 限流处理,对于超过流量限制的消息,直接做扔弃处理。默认TPS限制为2048条/s,此限制可以设置。 22 | ## 测试结果 23 | ### 测试环境 24 | | 环境 | 值 | 25 | | --- | --- | 26 | | CPU | Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz 8 cores | 27 | | RAM | 8 GB,1600MHz | 28 | | 硬盘IO | 1 TB,7200rpm | 29 | | 网卡 | 1 Gigabit Ethernet | 30 | | 操作系统 | 1 SMP Debian 3.16.7-ckt11-1+deb8u2 (2015-07-17) x86_64 GNU/Linux | 31 | | 网络ping值(ip具体值替换成*) | 64 bytes from 10.141.4. *: icmp_seq=2 ttl=55 time=0.718 ms
64 bytes from 10.141.4.*: icmp_seq=3 ttl=55 time=0.694 ms
64 bytes from 10.141.4.*: icmp_seq=4 ttl=55 time=0.711 ms | 32 | 33 | ### 1 、对应用响应时间的影响 34 | 具体步骤如下: 35 | 1、 记录没有Cicada的响应时间,记做A 36 | 2、 记录有Cicada的响应时间,记做B 37 | 3、 处理Cicada的时间 = B – A 38 | 为了保证数据的准确性,可以多测试几次,求平均值 39 | 40 | #### 测试最坏情况下,处理cicada的时间 41 | 一、1个RPC包含3条cicada 42 | 二、每个请求测试1w次,并发数为1,线性发送 43 | 44 | |序数|无cicada时处理时间(单位:ms/条)|有cicada时的处理时间(单位:ms/条)|单条处理时间(单位:ms/条) | 45 | |----|---|---|---| 46 | |1|0.28|1.077|0.266| 47 | |2|0.234|0.995|0.254| 48 | |3|0.239|1.006|0.256| 49 | 50 | #### 测试并发情况下,处理cicada的时间 51 | 一、同上 52 | 二、每个请求测试1w次,并发数100 53 | 54 | | 序数 | 无cicada时处理时间(单位:ms/条)| 有cicada时的处理时间(单位:ms/条) | 单条处理时间(单位:ms/条) | 55 | | --- | --- | --- | --- | 56 | | 4 | 0.081 | 0.483 | 0.134 | 57 | | 5 | 0.068 | 0.495 | 0.142 | 58 | 59 | 总结:通常情况下,一个客户端请求,会调用3次cicada,按照上面的测试数据来看,时间消耗在0.415ms-0.775ms之间,请求越多处理时间越快(批处理的缘故)。对于多数应用来说这点时间上的影响基本可以忽略。 60 | 61 | ### 2、 系统资源使用情况 62 | 测试方式:在系统中模拟用户行为并发发送日志请求。由于cicada客户端占用的资源较少, 63 | Cpu和mem的占比总是在不停的变化中,以下数据是截取某一个时刻的数值,仅作参考。 64 | 65 | |并发请求数 |Cpu%(共800%)|Mem%| 66 | |---|----|---| 67 | |75|2%|7% | 68 | |150|4%|7% | 69 | |225|5%|9.3% | 70 | |1000|18.3%|9.6%| 71 | 总结:随着并发数的增加,cpu%的增长基本成线性,并且数值较少,内存的变化也相对较少。 -------------------------------------------------------------------------------- /cicada-docs/cicada-client-quick-start.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/cicada-client-quick-start.md -------------------------------------------------------------------------------- /cicada-docs/cicada_demo_guide.md: -------------------------------------------------------------------------------- 1 | # cicada-demo使用指南 2 | 3 | ## 目录 4 | cicada\cicada-demo 5 | ## 目的 6 | 演示cicada-client使用,如拦截http访问、dubbo、注解..... 7 | ## 环境搭建 8 | ### 1、 安装zookeeper并修改zk服务地址 9 | 修改application.yml zookeeper的ip和端口,默认为本地 10 | ### 2、搭建nginx,配置nginx开启日志收集功能(LUA_JIT),日志将以Http Post的方式发送到nginx 11 | Nginx搭建好后,修改application.yml中nginx地址,provicer和consumer都需要修改 12 | 补充说明:不操作此步骤的话,消费发送失败而已,不影响演示 13 | ### 3、 启动 14 | cicada-demo-provider (生产者) 15 | cada-demo-consumer-web (消费者) 16 | 启动成功后,在url上输入 17 | http://localhost:8080/test //普通测试 18 | 显示Hello test即为成功 -------------------------------------------------------------------------------- /cicada-docs/cicada_statistic_design.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | # 背景和目标 3 | cicada的统计任务,是针对整个公司的服务在一段时间内产生的所有业务调用进行统计。如果统计任务分配到单节点,一方面数据量巨大,单机的内存和计算资源可能难以承受;另一方面会存在单点问题。 4 | 因此需要设计一个合理的分布式计算框架。主要从以下两个方面进行考虑: 5 | + 实现对等节点的集群管理,保证统计系统的伸缩性与可靠性。 6 | + 合理地对统计任务进行分片,保证将统计的数据和计算量均匀地分配到各计算节点上。 7 | 8 | ## 集群管理方案 9 | 调研了多种集群管理的开源方案,按照管理逻辑是否嵌入到JVM进程,分为分离式集群管理、内嵌式集群管理方案两种。 10 | 11 | ### 分离式集群管理——zookeeper 12 | 集群管理与业务代码分开部署。同类产品consul,doozerd,etcd。 13 | 14 | **优点** 15 | + 管理层与业务逻辑分离,层次清晰; 16 | + 业务节点之间不需要通信,减少耦合 17 | 18 | **缺点** 19 | + 依赖外部服务; 20 | + 运维复杂度以及硬件成本稍微高一些 21 | 22 | ### 内嵌式集群管理——hazelcast 23 | 将集群管理的代码、功能内嵌到JVM进程之中。同类产品:Coherence, Terracotta 24 | 25 | **优点** 26 | + 用户不需要额外配置类似zk的集群管理框架,接入简单; 27 | + 集群管理对用户透明; 28 | + 降低运维和硬件成本。 29 | 30 | **缺点** 31 | + 现有的开源产品,倾向于作为分布式缓存来使用,提供的功能大而全,集群管理作为附带功能 32 | + 缺少成熟的应用案例 33 | + 基于广播的动态节点增删,节点之前消息同步较频繁,可能引发广播风暴。 34 | 35 | 【结论】 36 | 如果自行开发分布式框架,需要解决节点通信、状态同步、选主、处理failover等各种问题,开发复杂度较高,周期过长,暂不考虑。 37 | 我们认为外置的集群管理,其硬件以及运维成本在可控的范围之内,而内嵌式的集群管理存在诸多问题,各种开源组件缺乏成熟的案例作支撑。最终选择使用zookeeper实现集群管理的功能。 38 | 39 | # 整体设计 40 | ## 分布式统计架构 41 | 如下图所示。 42 | ![cicada-statistic-architecture.jpg](static/images/cicada_statistic_architecture.jpg) 43 | 44 | ## 模块说明 45 | ### Zookeeper 46 | 引入zookeeper,负责集群配置管理、自动选Master、任务同步等;支持统计节点动态伸缩。 47 | 48 | ### 统计节点之Master 49 | + Master节点是具有任务分配功能的统计节点。 50 | + 没有固定的master,主挂之后自动选举新的master。 51 | 52 | 主要负责以下功能逻辑: 53 | + 作为统计节点,参与数据统计任务的执行。 54 | + 任务分片及节点任务分配 55 | - 根据当前alive的节点列表,分配各节点任务分片; 56 | - 更新zookeeper上的节点任务信息。 57 | 58 | ### 统计节点之Slave 59 | + 监听zookeeper上的任务节点,watch到变更之后,找到自身对应的任务分片,从ES中获取数据执行统计任务。 60 | 61 | # 详细设计 62 | ## 任务分片 63 | 统计任务的过程,就是从Elastic Search中取出对应时间段的Span数据(每个Span对应一次跨服务的调用),根据Span的App(应用名称)、Service(接口名称)、Method(方法)分组之后,再进行排序、统计之类的操作。 64 | 65 | **分片逻辑** 66 | + 针对Span数据的APP、Service、Method信息进行hash,然后对分片的Slot(分片总数,默认是1024)取模,得出的结果就是每条数据的sliceNo。 67 | + 每个计算节点负责 0~slot 区域的一个子区间,比如机器1负责0~255,机器2负责256~511 ……。 68 | + 每台计算节点从elasticsearch取数据的时候,只取sliceNo在自己负责的区间范围的数据进行统计。 69 | + 所有来自相同App、Service、Method的Span数据,在统计的时候都会落到同一个计算节点上,所以统计结果不需要进行合并,直接落库存储即可。而且以Method区分数据维度的方式,粒度比较细,可以保证各计算节点的数据量和计算量相对均匀。 70 | 71 | ## Zookeeper node设计 72 | ### /infra/cicada/web/master 73 | + Node类型 74 | 临时节点 75 | + Node内容 76 | master节点信息 77 | + 说明 78 | 统计系统启动时设置此节点,所有节点监听此节点变化。若此节点消失,触发自动选主。 79 | 80 | ### /infra/cicada/web/instances 81 | + Node类型 82 | 永久性node 83 | + Node内容 84 | 所有统计节点列表,每个统计节点是一个临时node。node列表示例如下所示: 85 | ``` 86 | /infra/cicada/web/instance 87 | |---- /node-1 88 | `---- /node-2 89 | ``` 90 | + 说明 91 | Master发起统计任务时,需要首先获取此临时node的内容,然后为分配各个计算节点的hash分片。 92 | 93 | ### /infra/cicada/web/job 94 | + Node类型 95 | 永久性node 96 | + Node内容 97 | 所有节点的统计任务,包括分片信息,统计的数据时间段等 98 | + 备注 99 | 由master设置此node的值,所有节点监听此node。Node内容变更之后触发各统计节点根据node内容执行各自的任务分片。 100 | 101 | ## 程序启动逻辑 102 | ![cicada-statistic-init.jpg](static/images/cicada_statistic_init.jpg) 103 | 104 | ## 选主逻辑 105 | + 第一个注册的节点成为master节点 106 | + 所有注册节点监听/master节点变更,若/master失效,触发自动选注逻辑。所有节点发起create /master节点的任务,创建成功的成为master节点。 107 | 108 | ## 节点动态变更 109 | + 新增节点自动到/instances下注册自身,临时节点。 110 | + 节点失效,临时节点会消失。 111 | 112 | ## 统计任务流程 113 | 如下图。 114 | ![cicada-statistic-process.jpg](static/images/cicada_statistic_process.jpg) 115 | ### 流程说明 116 | Master节点定期发起统计任务,步骤上图所示: 117 | + Master到zookeeper获取节点列表; 118 | + 根据节点信息,为各节点分配任务; 119 | + Master到zookeeper上更新任务; 120 | + 各统计节点(master && slave)监听到zookeeper任务信息变更,获取任务信息; 121 | + 统计节点根据各自的任务分片,到elastic search上拉取对应的分片数据; 122 | + 各节点执行统计任务,统计结果入mysql。 123 | -------------------------------------------------------------------------------- /cicada-docs/static/images/a_distribution_trace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/a_distribution_trace.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cat_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cat_architecture.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_architecture.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_dashboard_app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_dashboard_app.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_dashboard_method.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_dashboard_method.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_dashboard_report.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_dashboard_report.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_dashboard_service.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_dashboard_service.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_dashboard_trace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_dashboard_trace.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_deployment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_deployment.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_deployment_nginx_ha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_deployment_nginx_ha.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_statistic_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_statistic_architecture.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_statistic_init.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_statistic_init.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_statistic_process.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_statistic_process.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/cicada_web_swagger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/cicada_web_swagger.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/distribution_trace_model.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/distribution_trace_model.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/eagle_eye_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/eagle_eye_architecture.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/hydra_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/hydra_architecture.jpg -------------------------------------------------------------------------------- /cicada-docs/static/images/zipkin_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-docs/static/images/zipkin_architecture.jpg -------------------------------------------------------------------------------- /cicada-nginx/cronolog-1.6.2.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-nginx/cronolog-1.6.2.tar.gz -------------------------------------------------------------------------------- /cicada-nginx/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | function init() { 5 | sudo yum groupinstall -y Base "Development Tools" "Perl Support" 6 | sudo yum install -y zlib zlib-devel 7 | } 8 | 9 | function install_cronolog() { 10 | tar xf cronolog-1.6.2.tar.gz 11 | cd cronolog-1.6.2 12 | ./configure && make -j8 && sudo make install 13 | cd .. 14 | } 15 | 16 | function install_nginx() { 17 | tar xf ./nginx.tar.gz 18 | cd nginx 19 | bash ./install_tengine.sh 20 | cd .. 21 | } 22 | 23 | ## main 24 | init 25 | install_cronolog 26 | install_nginx 27 | 28 | -------------------------------------------------------------------------------- /cicada-nginx/nginx.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yirendai/cicada/ffebb9fdb96a677cfcbeff07396a03da5a61719b/cicada-nginx/nginx.tar.gz -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/Application.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @SpringBootApplication 8 | @EnableScheduling 9 | public class Application { 10 | public static void main(final String... args) { 11 | SpringApplication.run(Application.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/ApplicationStartup.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada; 2 | 3 | import com.yirendai.infra.cicada.cluster.ClusterJobMonitor; 4 | import com.yirendai.infra.cicada.cluster.ClusterLeaderManager; 5 | import com.yirendai.infra.cicada.cluster.ClusterNodeRegister; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.ApplicationListener; 9 | import org.springframework.context.event.ContextRefreshedEvent; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Component 13 | public class ApplicationStartup implements ApplicationListener { 14 | @Autowired 15 | private ClusterJobMonitor jobListener; 16 | 17 | @Autowired 18 | private ClusterNodeRegister nodeRegister; 19 | 20 | @Autowired 21 | private ClusterLeaderManager leaderManager; 22 | 23 | private void start() { 24 | // 首先监听JOB 25 | jobListener.start(); 26 | 27 | // 注册node节点 28 | nodeRegister.register(); 29 | 30 | // 执行选主逻辑 31 | leaderManager.start(); 32 | } 33 | 34 | @Override 35 | public void onApplicationEvent(final ContextRefreshedEvent event) { 36 | start(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/api/rest/EntityApi.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.api.rest; 2 | 3 | import com.jcabi.aspects.Loggable; 4 | import com.yirendai.infra.cicada.constants.ApiDocs; 5 | import com.yirendai.infra.cicada.constants.AppError; 6 | import com.yirendai.infra.cicada.entity.SpanEntity; 7 | import com.yirendai.infra.cicada.entity.model.SpanModel; 8 | import com.yirendai.infra.cicada.exception.BadRequestException; 9 | import com.yirendai.infra.cicada.request.EntityPageRequest; 10 | import com.yirendai.infra.cicada.service.SpanService; 11 | import com.yirendai.infra.cicada.service.TraceService; 12 | 13 | import io.swagger.annotations.ApiOperation; 14 | 15 | import lombok.extern.slf4j.Slf4j; 16 | 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.web.bind.annotation.PathVariable; 19 | import org.springframework.web.bind.annotation.RequestBody; 20 | import org.springframework.web.bind.annotation.RequestMapping; 21 | import org.springframework.web.bind.annotation.RequestMethod; 22 | import org.springframework.web.bind.annotation.RestController; 23 | 24 | import java.util.List; 25 | 26 | @Slf4j 27 | @Loggable 28 | @RestController 29 | @RequestMapping(value = "/cicada/api/v1/entities") 30 | public class EntityApi { 31 | @Autowired 32 | TraceService traceService; 33 | 34 | @Autowired 35 | SpanService spanService; 36 | 37 | /** 38 | * 分页获取span. 39 | */ 40 | @RequestMapping(value = "/spans", method = RequestMethod.POST) 41 | @ApiOperation(value = ApiDocs.FETCH_SPAN_PAGE, notes = ApiDocs.FETCH_SPAN_PAGE) 42 | public List fetchSpansPage(@RequestBody final EntityPageRequest request) { 43 | if (!request.isValid()) { 44 | log.error("request invalid error : fetch span pages request's param incomplete!"); 45 | throw new BadRequestException(AppError.INCOMPLETE_PAGE_REQUEST_PARAMS); 46 | } 47 | 48 | return spanService.fetchSpanPage(request); 49 | } 50 | 51 | /** 52 | * 分页获取采集到异常的span信息. 53 | */ 54 | @RequestMapping(value = "/errorspans", method = RequestMethod.POST) 55 | @ApiOperation(value = ApiDocs.FETCH_ERROR_SPAN_PAGE, notes = ApiDocs.FETCH_ERROR_SPAN_PAGE) 56 | public List fetchErrorSpansPage(@RequestBody final EntityPageRequest request) { 57 | if (!request.isValid()) { 58 | log.error("request invalid error : fetch span pages request's param incomplete!"); 59 | throw new BadRequestException(AppError.INCOMPLETE_PAGE_REQUEST_PARAMS); 60 | } 61 | 62 | return spanService.fetchErrorSpanPage(request); 63 | } 64 | 65 | /** 66 | * 根据TraceId获取整个trace调用链的信息. 67 | */ 68 | @RequestMapping(value = "/traces/{traceId}", method = RequestMethod.GET) 69 | @ApiOperation(value = ApiDocs.FETCH_TRACE_CHAIN, notes = ApiDocs.FETCH_TRACE_CHAIN) 70 | public List fetchTraceChain(@PathVariable("traceId") final String traceId) { 71 | return traceService.fetchTraceChain(traceId); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/api/rest/StatisInfoApi.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.api.rest; 2 | 3 | import com.jcabi.aspects.Loggable; 4 | import com.yirendai.infra.cicada.constants.ApiDocs; 5 | import com.yirendai.infra.cicada.constants.AppError; 6 | import com.yirendai.infra.cicada.entity.SpanStatisInfo; 7 | import com.yirendai.infra.cicada.exception.BadRequestException; 8 | import com.yirendai.infra.cicada.request.StatisInfoPageRequest; 9 | import com.yirendai.infra.cicada.request.StatisInfoRequest; 10 | import com.yirendai.infra.cicada.service.SpanStatisInfoService; 11 | 12 | import io.swagger.annotations.ApiOperation; 13 | 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.data.domain.Page; 16 | import org.springframework.data.domain.PageRequest; 17 | import org.springframework.data.domain.Pageable; 18 | import org.springframework.web.bind.annotation.RequestBody; 19 | import org.springframework.web.bind.annotation.RequestMapping; 20 | import org.springframework.web.bind.annotation.RequestMethod; 21 | import org.springframework.web.bind.annotation.RestController; 22 | 23 | import java.util.List; 24 | 25 | @RestController 26 | @Loggable 27 | @RequestMapping(value = "/cicada/api/v1/statisinfos") 28 | public class StatisInfoApi { 29 | @Autowired 30 | SpanStatisInfoService spanService; 31 | 32 | /** 33 | * 获取指定时间段、指定服务的所有Span统计信息. 34 | */ 35 | @RequestMapping(value = "/spans/all", method = RequestMethod.POST) 36 | @ApiOperation(value = ApiDocs.FETCH_SPAN_STATIS_INFO_PAGE, notes = ApiDocs.FETCH_SPAN_STATIS_INFO_PAGE) 37 | public List fetchSpanStatisInfoByDuration(@RequestBody final StatisInfoRequest request) { 38 | return spanService.fetchAllByDuration(request); 39 | } 40 | 41 | /** 42 | * 获取指定时间段、指定服务的分页Span统计信息. 43 | */ 44 | @RequestMapping(value = "/spans", method = RequestMethod.POST) 45 | @ApiOperation(value = ApiDocs.FETCH_SPAN_STATIS_INFO_PAGE, notes = ApiDocs.FETCH_SPAN_STATIS_INFO_PAGE) 46 | public Page fetchSpanStatisInfoPageByDuration(@RequestBody final StatisInfoPageRequest request) { 47 | if (!request.isValid()) { 48 | throw new BadRequestException(AppError.INCOMPLETE_PAGE_REQUEST_PARAMS); 49 | } 50 | 51 | final Pageable pageable = new PageRequest(request.getPage(), request.getSize()); 52 | return spanService.fetchPage(request, pageable); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/cluster/ClusterJobMonitor.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.cluster; 2 | 3 | import org.apache.curator.framework.recipes.cache.NodeCache; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.io.IOException; 8 | 9 | @Component 10 | public class ClusterJobMonitor { 11 | @Autowired 12 | private NodeCache jobCache; 13 | 14 | @Autowired 15 | private JobProcessor jobProcessor; 16 | 17 | public void start() { 18 | jobCache.getListenable().addListener(jobProcessor); 19 | } 20 | 21 | public void close() { 22 | try { 23 | jobCache.close(); 24 | } catch (IOException ex) { 25 | // do not need any process 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/cluster/ClusterLeaderManager.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.cluster; 2 | 3 | import com.yirendai.infra.cicada.configure.CicadaWebProps; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import org.apache.curator.framework.CuratorFramework; 8 | import org.apache.curator.framework.recipes.leader.LeaderSelector; 9 | import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter; 10 | import org.apache.curator.framework.state.ConnectionState; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.concurrent.atomic.AtomicBoolean; 16 | 17 | import javax.annotation.PostConstruct; 18 | 19 | @Slf4j 20 | @Component 21 | public class ClusterLeaderManager extends LeaderSelectorListenerAdapter { 22 | private static LeaderSelector leaderSelector; 23 | private final AtomicBoolean isStop; 24 | 25 | @Autowired 26 | private CicadaWebProps props; 27 | @Autowired 28 | private CuratorFramework zkClient; 29 | 30 | public ClusterLeaderManager() { 31 | super(); 32 | this.isStop = new AtomicBoolean(false); 33 | } 34 | 35 | @PostConstruct 36 | public void init() { 37 | leaderSelector = new LeaderSelector(zkClient, props.getMasterNodePath(), this); 38 | leaderSelector.autoRequeue(); 39 | } 40 | 41 | public static boolean isLeader() { 42 | return leaderSelector.hasLeadership(); 43 | } 44 | 45 | public void start() { 46 | leaderSelector.start(); 47 | } 48 | 49 | public void close() { 50 | leaderSelector.close(); 51 | } 52 | 53 | @Override 54 | public void takeLeadership(final CuratorFramework client) { 55 | while (true) { 56 | if (isStop.get()) { 57 | isStop.set(false); 58 | break; 59 | } 60 | 61 | try { 62 | TimeUnit.SECONDS.sleep(3); 63 | } catch (InterruptedException ex) { 64 | log.warn("interrupted sleep, error:{}", ex); 65 | } 66 | } 67 | } 68 | 69 | @Override 70 | public void stateChanged(final CuratorFramework client, final ConnectionState state) { 71 | if (state == ConnectionState.LOST || state == ConnectionState.SUSPENDED) { 72 | log.warn("connection state changed, now"); 73 | isStop.set(true); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/cluster/ClusterNodeRegister.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.cluster; 2 | 3 | import com.yirendai.infra.cicada.configure.CicadaWebProps; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import org.apache.curator.framework.CuratorFramework; 8 | import org.apache.zookeeper.CreateMode; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.UUID; 13 | 14 | @Slf4j 15 | @Component 16 | public class ClusterNodeRegister { 17 | private static final String NODE_LABEL = UUID.randomUUID().toString(); 18 | private static final String PATH_SEPERATOR = "/" ; 19 | 20 | @Autowired 21 | private CicadaWebProps props; 22 | 23 | @Autowired 24 | private CuratorFramework zkClient; 25 | 26 | public static String getNodeLabel() { 27 | return NODE_LABEL; 28 | } 29 | 30 | public void register() { 31 | 32 | final String nodePath = buildNodePath(); 33 | 34 | try { 35 | zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(nodePath); 36 | } catch (Exception ex) { 37 | log.error("failed create znode: {}, error: {}", nodePath, ex); 38 | // System.exit(-1); 39 | } 40 | } 41 | 42 | private String buildNodePath() { 43 | final StringBuilder sb = new StringBuilder(); 44 | sb.append(props.getInstancesNodePath()).append(PATH_SEPERATOR).append(NODE_LABEL); 45 | return sb.toString(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/cluster/JobProcessor.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.cluster; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.yirendai.infra.cicada.entity.Fragment; 5 | import com.yirendai.infra.cicada.entity.Job; 6 | import com.yirendai.infra.cicada.entity.JobSlice; 7 | import com.yirendai.infra.cicada.service.StatisticService; 8 | 9 | import org.apache.curator.framework.recipes.cache.NodeCache; 10 | import org.apache.curator.framework.recipes.cache.NodeCacheListener; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | 15 | @Component 16 | public class JobProcessor implements NodeCacheListener { 17 | @Autowired 18 | private NodeCache jobCache; 19 | 20 | @Autowired 21 | private StatisticService service; 22 | 23 | @Override 24 | public void nodeChanged() { 25 | final String jobStr = new String(jobCache.getCurrentData().getData()); 26 | final JobSlice slice = genJobSlice(jobStr); 27 | service.run(slice); 28 | } 29 | 30 | private JobSlice genJobSlice(final String jobStr) { 31 | final Job job = JSON.parseObject(jobStr, Job.class); 32 | final Fragment fragment = job.getJobFragment(ClusterNodeRegister.getNodeLabel()); 33 | 34 | final JobSlice jobSlice = new JobSlice(); 35 | jobSlice.setStartTimestamp(job.getStartTimestamp()); 36 | jobSlice.setEndTimestamp(job.getEndTimestamp()); 37 | jobSlice.setStart(fragment.getStart()); 38 | jobSlice.setEnd(fragment.getEnd()); 39 | 40 | return jobSlice; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/configure/CicadaWebProps.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.configure; 2 | 3 | import lombok.Getter; 4 | 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Getter 9 | @Component 10 | public class CicadaWebProps { 11 | @Value("${elasticsearch.node.addr}") 12 | private String esNodeAddr; 13 | 14 | @Value("${elasticsearch.node.port}") 15 | private int esNodePort; 16 | 17 | @Value("${elasticsearch.cluster.name}") 18 | private String esClusterName; 19 | 20 | @Value("${elasticsearch.bulk.await.minutes}") 21 | private int esBulkAwaitMinutes; 22 | 23 | @Value("${elasticsearch.index.type.name}") 24 | private String esTypeName; 25 | 26 | @Value("${elasticsearch.index.span.prefix}") 27 | private String esSpanIndexPrefix; 28 | 29 | @Value("${elasticsearch.index.annotation.prefix}") 30 | private String esAnnotationIndexPrefix; 31 | 32 | @Value("${elasticsearch.index.retention.day}") 33 | private int esIndexRetentionDays; 34 | 35 | @Value("${statistic.zookeeper.node.master}") 36 | private String masterNodePath; 37 | 38 | @Value("${statistic.zookeeper.node.instances}") 39 | private String instancesNodePath; 40 | 41 | @Value("${statistic.zookeeper.node.job}") 42 | private String jobNodePath; 43 | 44 | @Value("${job.slot.range}") 45 | private int jobSlotRange; 46 | 47 | @Value("${statistic.zookeeper.connection}") 48 | private String zkAddr; 49 | 50 | @Value("${statistic.zookeeper.namespace}") 51 | private String zkNamespase; 52 | } 53 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/configure/CuratorZookeeperConfigure.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.configure; 2 | 3 | import com.yirendai.infra.cicada.util.ZookeeperUtil; 4 | 5 | import lombok.SneakyThrows; 6 | 7 | import org.apache.curator.framework.CuratorFramework; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | @Configuration 13 | public class CuratorZookeeperConfigure { 14 | private static final char PATH_SEPARATOR = '/'; 15 | private static final String CICADA_NAMESPACE_NODE_CONTENT = "cicada namespace"; 16 | 17 | @Autowired 18 | private CicadaWebProps props; 19 | 20 | @Bean 21 | @SneakyThrows 22 | public CuratorFramework zkClient() { 23 | this.createNamespaceIfNotExists(); 24 | final CuratorFramework zkClient = ZookeeperUtil.getClient(props.getZkAddr(), props.getZkNamespase()); 25 | zkClient.start(); 26 | return zkClient; 27 | } 28 | 29 | /** 30 | * 如果zk中cicada的namespace不存在,则创建. 31 | */ 32 | 33 | @SneakyThrows 34 | private void createNamespaceIfNotExists() { 35 | final CuratorFramework client = ZookeeperUtil.getClient(props.getZkAddr()); 36 | 37 | String namespace = props.getZkNamespase(); 38 | if (namespace.charAt(0) != PATH_SEPARATOR) { 39 | final StringBuilder sb = new StringBuilder(); 40 | sb.append(PATH_SEPARATOR).append(namespace); 41 | namespace = sb.toString(); 42 | } 43 | 44 | client.start(); 45 | try { 46 | if (!ZookeeperUtil.exists(client, namespace)) { 47 | ZookeeperUtil.create(client, namespace, CICADA_NAMESPACE_NODE_CONTENT); 48 | } 49 | } finally { 50 | client.close(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/configure/JobCacheConfigure.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.configure; 2 | 3 | import com.yirendai.infra.cicada.util.ZookeeperUtil; 4 | 5 | import lombok.SneakyThrows; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import org.apache.curator.framework.CuratorFramework; 9 | import org.apache.curator.framework.recipes.cache.NodeCache; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | @Slf4j 15 | @Configuration 16 | public class JobCacheConfigure { 17 | private static final String CICADA_JOBNODE_DEFAULT_CONTENT = "jobNode"; 18 | 19 | @Autowired 20 | private CicadaWebProps props; 21 | 22 | @Autowired 23 | private CuratorFramework zkClient; 24 | 25 | @Bean 26 | public NodeCache jobCache() { 27 | final String jobNodePath = props.getJobNodePath(); 28 | createJobNodeIfNotExists(jobNodePath); 29 | 30 | final NodeCache jobCache = new NodeCache(zkClient, jobNodePath, false); 31 | try { 32 | jobCache.start(); 33 | } catch (Exception ex) { 34 | log.error("failed start jobCache on path: {}, error: {}", jobNodePath, ex); 35 | } 36 | 37 | return jobCache; 38 | } 39 | 40 | @SneakyThrows 41 | private void createJobNodeIfNotExists(final String nodePath) { 42 | if (!ZookeeperUtil.exists(zkClient, nodePath)) { 43 | ZookeeperUtil.create(zkClient, nodePath, CICADA_JOBNODE_DEFAULT_CONTENT); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/configure/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.configure; 2 | 3 | import static springfox.documentation.builders.PathSelectors.regex; 4 | 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import springfox.documentation.builders.ApiInfoBuilder; 9 | import springfox.documentation.builders.RequestHandlerSelectors; 10 | import springfox.documentation.service.ApiInfo; 11 | import springfox.documentation.spi.DocumentationType; 12 | import springfox.documentation.spring.web.plugins.Docket; 13 | import springfox.documentation.swagger.web.UiConfiguration; 14 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 15 | 16 | @Configuration 17 | @EnableSwagger2 18 | public class SwaggerConfig { 19 | @Bean 20 | public Docket documentation() { 21 | return new Docket(DocumentationType.SWAGGER_2) // 22 | .select() // 23 | .apis(RequestHandlerSelectors.any()) // 24 | .paths(regex("/.*")) 25 | .build().apiInfo(metadata()); 26 | } 27 | 28 | @Bean 29 | public UiConfiguration uiConfig() { 30 | return UiConfiguration.DEFAULT; 31 | } 32 | 33 | private ApiInfo metadata() { 34 | return new ApiInfoBuilder().title("cicada-web API") // 35 | .description("cicada-web API") // 36 | .version("1.0").build(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/constants/ApiDocs.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.constants; 2 | 3 | public class ApiDocs { 4 | // for ProjectInfoServiceApi 5 | public static final String SEARCH_APPS_PAGE = "分页查看所有项目信息"; 6 | public static final String SEARCH_APP_SERVICES_PAGE = "分页查询app下的service信息"; 7 | public static final String SEARCH_APP_SERVICE_METHODS_PAGE = "分页获取service下的method详情"; 8 | 9 | // for StatisInfoApi 10 | public static final String FETCH_TRACE_STATIS_INFO_PAGE = "获取指定时间段、指定服务的所有trace统计信息"; 11 | public static final String FETCH_SPAN_STATIS_INFO_PAGE = "获取指定时间段、指定服务的所有Span统计信息"; 12 | 13 | // for EntityApi 14 | public static final String FETCH_TRACE_PAGE = "分页获取Trace信息"; 15 | public static final String FETCH_SPAN_PAGE = "分页获取Span信息"; 16 | public static final String FETCH_ERROR_SPAN_PAGE = "分页获取异常Span信息"; 17 | public static final String FETCH_TRACE_CHAIN = "根据TraceId获取整个trace调用链的信息"; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/constants/AppError.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.constants; 2 | 3 | /** 4 | * 错误信息定义. 5 | * @author zeche 6 | */ 7 | public enum AppError { 8 | 9 | INCOMPLETE_PAGE_REQUEST_PARAMS(2001, "page.request.params.incomplete"), 10 | 11 | OTHER_METHOD_ARGS_NOT_VALID(9000, ""), OTHER_HTTP_MEDIATYPE_NOT_SUPPORT(9001, 12 | "other.contenttype.unsupport"), OTHER_HTTP_MESSAGE_NOT_READABLE(9002, 13 | "other.message.not.readable"), OTHER_HTTP_TYPE_MISMATCH(9003, 14 | "other.type.mismatch"), OTHER_SERVER_INERNAL_EXCEPTION(9999, "other.server.internal.error"); 15 | 16 | private int errorCode; 17 | private String messageKey; 18 | 19 | AppError(final int code, final String messageKey) { 20 | this.errorCode = code; 21 | this.messageKey = messageKey; 22 | } 23 | 24 | public int getErrorCode() { 25 | return this.errorCode; 26 | } 27 | 28 | public String getMessageKey() { 29 | return this.messageKey; 30 | } 31 | 32 | public static AppError valueOf(final int errorCode) { 33 | AppError appError = null; 34 | for (final AppError error : values()) { 35 | if (error.getErrorCode() == errorCode) { 36 | appError = error; 37 | break; 38 | } 39 | } 40 | 41 | return appError; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/entity/Fragment.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class Fragment { 11 | private int start; 12 | private int end; 13 | } 14 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/entity/Job.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | public class Job { 14 | private long id; 15 | private long startTimestamp; 16 | private long endTimestamp; 17 | private Map infos; 18 | 19 | public Job() { 20 | this.infos = new HashMap(); 21 | } 22 | 23 | public void addJobFragment(final String key, final Fragment fragment) { 24 | infos.put(key, fragment); 25 | } 26 | 27 | public Fragment getJobFragment(final String key) { 28 | return infos.get(key); 29 | } 30 | 31 | public void incrJodId() { 32 | ++this.id; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return JSON.toJSONString(this); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/entity/JobEntity.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class JobEntity { 7 | private long jobId; 8 | private String key; 9 | private String desc; // 任务描述信息 10 | private String status; // 任务完成状态(完成、异常中断) 11 | } 12 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/entity/JobSlice.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | 5 | import lombok.Data; 6 | 7 | @Data 8 | public class JobSlice { 9 | private long startTimestamp; 10 | private long endTimestamp; 11 | private int start; 12 | private int end; 13 | 14 | @Override 15 | public String toString() { 16 | return JSON.toJSONString(this); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/entity/SpanStatisInfo.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFormat; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import com.fasterxml.jackson.datatype.joda.ser.DateTimeSerializer; 6 | import com.yirendai.infra.cicada.constants.DateTimeFormats; 7 | 8 | import lombok.Data; 9 | import lombok.EqualsAndHashCode; 10 | import lombok.NoArgsConstructor; 11 | 12 | import org.joda.time.DateTime; 13 | 14 | import javax.persistence.Entity; 15 | import javax.persistence.GeneratedValue; 16 | import javax.persistence.GenerationType; 17 | import javax.persistence.Id; 18 | import javax.persistence.Table; 19 | 20 | @Data 21 | @NoArgsConstructor 22 | @Entity 23 | @Table(name = "span_statis_info") 24 | @EqualsAndHashCode(callSuper = false) 25 | public class SpanStatisInfo extends StatisInfo { 26 | private static final long serialVersionUID = 3657478520301707196L; 27 | 28 | @Id 29 | @GeneratedValue(strategy = GenerationType.AUTO) 30 | private Long id; 31 | 32 | 33 | private int appId; 34 | private int serviceId; 35 | private int methodId; 36 | 37 | private long count; 38 | private double failureRate; 39 | 40 | private int line95Duration; 41 | private int line999Duration; 42 | 43 | private double avgDuration; 44 | private int minDuration; 45 | private int maxDuration; 46 | 47 | @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateTimeFormats.FULL_TIME_ENGLISH, 48 | timezone = DateTimeFormats.CHINESE_TIME_ZONE) 49 | @JsonSerialize(using = DateTimeSerializer.class) 50 | DateTime statisTime; 51 | } 52 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/entity/StatisInfo.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.entity; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | import java.io.Serializable; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | public class StatisInfo implements Serializable { 11 | 12 | private static final long serialVersionUID = 6108124532578856455L; 13 | 14 | private Long id; 15 | } 16 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/exception/BadRequestException.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.exception; 2 | 3 | import com.yirendai.infra.cicada.constants.AppError; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | import lombok.NoArgsConstructor; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @EqualsAndHashCode(callSuper = false) 14 | public class BadRequestException extends RuntimeException { 15 | 16 | private static final long serialVersionUID = 1L; 17 | 18 | private int errorCode; 19 | private String message; 20 | private String data; 21 | 22 | public BadRequestException(final AppError appError) { 23 | super(); 24 | this.errorCode = appError.getErrorCode(); 25 | this.message = appError.getMessageKey(); 26 | } 27 | 28 | public BadRequestException(final AppError appError, final String data) { 29 | super(); 30 | this.errorCode = appError.getErrorCode(); 31 | this.message = appError.getMessageKey(); 32 | this.data = data; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/exception/ErrorMessage.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.exception; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ErrorMessage { 7 | 8 | private long timestamp; 9 | private int code; 10 | private String message; 11 | private String data; 12 | 13 | public ErrorMessage() { 14 | super(); 15 | } 16 | 17 | public ErrorMessage(final int code, final String message) { 18 | this.code = code; 19 | this.message = message; 20 | this.timestamp = System.currentTimeMillis(); 21 | } 22 | 23 | public ErrorMessage(final int code, final String message, final String data) { 24 | this.code = code; 25 | this.message = message; 26 | this.data = data; 27 | this.timestamp = System.currentTimeMillis(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/exception/InternalServerErrorException.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.exception; 2 | 3 | import com.yirendai.infra.cicada.constants.AppError; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | import lombok.NoArgsConstructor; 9 | 10 | @Data 11 | @EqualsAndHashCode(callSuper = false) 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class InternalServerErrorException extends RuntimeException { 15 | private static final long serialVersionUID = 1L; 16 | 17 | private int errorCode; 18 | private String message; 19 | 20 | public InternalServerErrorException(final AppError appError) { 21 | super(); 22 | this.errorCode = appError.getErrorCode(); 23 | this.message = appError.getMessageKey(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/exception/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.exception; 2 | 3 | import com.yirendai.infra.cicada.constants.AppError; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.EqualsAndHashCode; 8 | import lombok.NoArgsConstructor; 9 | 10 | @Data 11 | @EqualsAndHashCode(callSuper = false) 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class NotFoundException extends RuntimeException { 15 | 16 | private static final long serialVersionUID = 1L; 17 | 18 | private int errorCode; 19 | private String message; 20 | 21 | public NotFoundException(final AppError appError) { 22 | super(); 23 | this.errorCode = appError.getErrorCode(); 24 | this.message = appError.getMessageKey(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/repository/AnnotationRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.yirendai.infra.cicada.configure.CicadaWebProps; 6 | import com.yirendai.infra.cicada.entity.model.AnnotationModel; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import org.elasticsearch.action.search.SearchRequestBuilder; 11 | import org.elasticsearch.action.search.SearchResponse; 12 | import org.elasticsearch.client.transport.TransportClient; 13 | import org.elasticsearch.index.query.BoolQueryBuilder; 14 | import org.elasticsearch.index.query.QueryBuilders; 15 | import org.elasticsearch.search.SearchHit; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Component; 18 | 19 | import java.util.LinkedList; 20 | import java.util.List; 21 | 22 | @Slf4j 23 | @Component 24 | public class AnnotationRepository { 25 | @Autowired 26 | private TransportClient client; 27 | 28 | @Autowired 29 | private CicadaWebProps props; 30 | 31 | /** 32 | * 根据traceId和spanId获取annotationModel列表. 33 | */ 34 | public List getSpanAnnotations(final String traceId, final String spanId) { 35 | // 声明SearchRequestBuilder实例 36 | final String indice = getDefaultIndice(); 37 | final SearchRequestBuilder builder = client.prepareSearch(indice); 38 | builder.setTypes(props.getEsTypeName()); 39 | 40 | // 设置查询条件 41 | final BoolQueryBuilder query = new BoolQueryBuilder(); 42 | query.must(QueryBuilders.termQuery("traceId", traceId)) // 43 | .must(QueryBuilders.termQuery("spanId", spanId)); 44 | 45 | // 执行查询 46 | final SearchResponse response = builder.setQuery(query).execute().actionGet(); 47 | 48 | // 处理返回结果 49 | final List annos = new LinkedList(); 50 | for (final SearchHit hit : response.getHits().hits()) { 51 | final String docStr = hit.getSourceAsString(); 52 | try { 53 | final AnnotationModel model = JSON.parseObject(docStr, AnnotationModel.class); 54 | annos.add(model); 55 | } catch (JSONException ex) { 56 | log.error("failed load data {} to AnnotationModel, error {}", docStr, ex); 57 | continue; 58 | } 59 | } 60 | 61 | return annos; 62 | } 63 | 64 | private String getDefaultIndice() { 65 | return props.getEsAnnotationIndexPrefix() + "_*"; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/repository/AppManagerRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.yirendai.infra.cicada.resource.RegisterInfoResource; 4 | import com.yirendai.infra.cicada.service.MethodService; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Map; 10 | 11 | @Component 12 | public class AppManagerRepository { 13 | @Autowired 14 | private MethodService methodService; 15 | 16 | public Map register(final String appName, // 17 | final String serviceName, // 18 | final String methodName) { 19 | return methodService.getMethodIdMap(appName, serviceName, methodName); 20 | } 21 | 22 | public RegisterInfoResource getRegisterInfo(final int methodId) { 23 | return methodService.getRegisterInfo(methodId); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/repository/SpanStatisInfoRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.yirendai.infra.cicada.entity.SpanStatisInfo; 4 | 5 | import org.joda.time.DateTime; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | import org.springframework.data.jpa.repository.JpaRepository; 9 | import org.springframework.data.jpa.repository.Modifying; 10 | import org.springframework.data.jpa.repository.Query; 11 | import org.springframework.data.repository.query.Param; 12 | 13 | import java.util.List; 14 | 15 | import javax.transaction.Transactional; 16 | 17 | @Transactional 18 | public interface SpanStatisInfoRepository extends JpaRepository { 19 | @Query("select t from SpanStatisInfo t where " 20 | + "t.methodId=:methodId " 21 | + "and t.statisTime >= :beginTime " 22 | + "and t.statisTime < :endTime " 23 | + "order by t.id desc") 24 | Page fetchPage(@Param("methodId") int methodId, 25 | @Param("beginTime") DateTime beginTime, 26 | @Param("endTime") DateTime endTime, Pageable pageable); 27 | 28 | @Query("select t from SpanStatisInfo t where " 29 | + "t.methodId=:methodId " 30 | + "and t.statisTime >= :beginTime " 31 | + "and t.statisTime < :endTime " 32 | + "order by t.statisTime asc") 33 | List findAllByDuration(@Param("methodId") int methodId, 34 | @Param("beginTime") DateTime beginTime, 35 | @Param("endTime") DateTime endTime); 36 | 37 | /** 38 | * 删除超过保存期限的统计数据. 39 | */ 40 | @Modifying 41 | @Query("delete from SpanStatisInfo t where t.statisTime < :expireTime") 42 | void cleanExpireInfos(@Param("expireTime") DateTime expireTime); 43 | } 44 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/repository/StatisInfoBulkRepository.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.repository; 2 | 3 | import com.yirendai.infra.cicada.entity.StatisInfo; 4 | 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.transaction.annotation.Transactional; 7 | 8 | import java.util.Collection; 9 | 10 | import javax.persistence.EntityManager; 11 | import javax.persistence.PersistenceContext; 12 | 13 | /** 14 | * 针对统计结果数据,批量数据插入. 15 | * @author zeche 16 | */ 17 | @Service 18 | @Transactional 19 | public class StatisInfoBulkRepository { 20 | private static final int BATCH_SIZE = 1000; 21 | 22 | @PersistenceContext 23 | private EntityManager entityManager; 24 | 25 | public void saveAll(final Collection entities) { 26 | if (entities.isEmpty()) { 27 | return; 28 | } 29 | 30 | int index = 0; 31 | for (final T entity : entities) { 32 | persistOrMerge(entity); 33 | ++index; 34 | if (index % BATCH_SIZE == 0 || index == entities.size() - 1) { 35 | entityManager.flush(); 36 | entityManager.clear(); 37 | } 38 | } 39 | } 40 | 41 | private T persistOrMerge(final T entity) { 42 | final T result; 43 | if (entity.getId() == null) { 44 | entityManager.persist(entity); 45 | result = entity; 46 | } else { 47 | result = entityManager.merge(entity); 48 | } 49 | 50 | return result; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/request/EntityPageRequest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | 10 | import org.joda.time.DateTime; 11 | 12 | /** 13 | * 业务方法调用查询请求. 14 | * @author Zecheng 15 | */ 16 | @Data 17 | @AllArgsConstructor 18 | public class EntityPageRequest { 19 | 20 | private Integer methodId; 21 | 22 | @ApiModelProperty(name = "beginTime", value = "ISO8601 time format", dataType = "string") 23 | private DateTime beginTime; 24 | 25 | @ApiModelProperty(name = "endTime", value = "ISO8601 time format", dataType = "string") 26 | private DateTime endTime; 27 | 28 | @ApiModelProperty(value = "区间查询条件:处理时间下限,默认为0") 29 | private int floorDuration; 30 | 31 | @ApiModelProperty(value = "区间查询条件:处理时间上限,默认100s") 32 | private int ceilDuration; 33 | 34 | private int page; 35 | private int size; 36 | 37 | public EntityPageRequest() { 38 | endTime = DateTime.now(); 39 | floorDuration = 0; 40 | ceilDuration = 100 * 1000; 41 | page = 0; 42 | size = 20; 43 | } 44 | 45 | @JsonIgnore 46 | public boolean isValid() { 47 | boolean valid = true; 48 | if (methodId == null || beginTime == null || ceilDuration <= 0) { 49 | valid = false; 50 | } 51 | 52 | return valid; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/request/StatisInfoPageRequest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | 10 | import org.joda.time.DateTime; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | public class StatisInfoPageRequest { 15 | 16 | private Integer methodId; 17 | @ApiModelProperty(name = "beginTime", value = "ISO8601 time format", dataType = "string") 18 | private DateTime beginTime; 19 | 20 | @ApiModelProperty(name = "endTime", value = "ISO8601 time format", dataType = "string") 21 | private DateTime endTime; 22 | 23 | int page; 24 | int size; 25 | 26 | public StatisInfoPageRequest() { 27 | this.endTime = DateTime.now(); 28 | this.page = 0; 29 | this.size = 20; 30 | } 31 | 32 | @JsonIgnore 33 | public boolean isValid() { 34 | final boolean valid; 35 | if (methodId == null || beginTime == null) { 36 | valid = false; 37 | } else { 38 | valid = page >= 0 && size > 0; 39 | } 40 | 41 | return valid; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/request/StatisInfoRequest.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.request; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | 10 | import org.joda.time.DateTime; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | public class StatisInfoRequest { 15 | 16 | private Integer methodId; 17 | @ApiModelProperty(name = "beginTime", value = "ISO8601 time format", dataType = "string") 18 | private DateTime beginTime; 19 | 20 | @ApiModelProperty(name = "endTime", value = "ISO8601 time format", dataType = "string") 21 | private DateTime endTime; 22 | 23 | public StatisInfoRequest() { 24 | this.endTime = DateTime.now(); 25 | } 26 | 27 | @JsonIgnore 28 | public boolean isValid() { 29 | return this.methodId != null && this.beginTime != null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/service/SpanService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.service; 2 | 3 | import com.jcabi.aspects.Loggable; 4 | import com.yirendai.infra.cicada.entity.model.SpanModel; 5 | import com.yirendai.infra.cicada.repository.SpanRepository; 6 | import com.yirendai.infra.cicada.request.EntityPageRequest; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | 13 | @Component 14 | @Loggable 15 | public class SpanService { 16 | @Autowired 17 | SpanRepository repo; 18 | 19 | @Autowired 20 | AppManagerService appManager; 21 | 22 | public List fetchSpanPage(final EntityPageRequest request) { 23 | return repo.fetchSpanModelPage(request); 24 | } 25 | 26 | public List fetchErrorSpanPage(final EntityPageRequest request) { 27 | return repo.fetchErrorSpanModelPage(request); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/service/SpanStatisInfoService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.service; 2 | 3 | import com.jcabi.aspects.Loggable; 4 | import com.yirendai.infra.cicada.entity.SpanStatisInfo; 5 | import com.yirendai.infra.cicada.repository.SpanStatisInfoRepository; 6 | import com.yirendai.infra.cicada.request.StatisInfoPageRequest; 7 | import com.yirendai.infra.cicada.request.StatisInfoRequest; 8 | 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.data.domain.Page; 11 | import org.springframework.data.domain.Pageable; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.List; 15 | 16 | @Component 17 | @Loggable 18 | public class SpanStatisInfoService { 19 | @Autowired 20 | SpanStatisInfoRepository repo; 21 | 22 | @Autowired 23 | AppManagerService appManager; 24 | 25 | public Page fetchPage(final StatisInfoPageRequest request, final Pageable pageable) { 26 | return repo.fetchPage(request.getMethodId(), request.getBeginTime(), request.getEndTime(), pageable); 27 | } 28 | 29 | public List fetchAllByDuration(final StatisInfoRequest request) { 30 | return repo.findAllByDuration(request.getMethodId(), request.getBeginTime(), request.getEndTime()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/service/StatisticService.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.service; 2 | 3 | import com.jcabi.aspects.Loggable; 4 | import com.yirendai.infra.cicada.entity.JobSlice; 5 | import com.yirendai.infra.cicada.entity.model.SpanModel; 6 | import com.yirendai.infra.cicada.repository.SpanRepository; 7 | import com.yirendai.infra.cicada.repository.StatisInfoBulkRepository; 8 | import com.yirendai.infra.cicada.task.LogStatistician; 9 | 10 | import org.joda.time.DateTime; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * 统计操作,定期收集日志,统计结果存储数据库. 18 | * @author Zecheng 19 | * 20 | */ 21 | @Component 22 | @Loggable 23 | public class StatisticService { 24 | @Autowired 25 | StatisInfoBulkRepository bulkRepo; 26 | 27 | @Autowired 28 | SpanRepository spanRepo; 29 | 30 | public void run(final JobSlice jobSlice) { 31 | process(jobSlice); 32 | } 33 | 34 | private void process(final JobSlice jobSlice) { 35 | // 收集日志 36 | final List models = spanRepo.collectSpan(jobSlice); 37 | if (models == null) { 38 | return; 39 | } 40 | 41 | // 统计 42 | final DateTime curTime = DateTime.now(); 43 | final LogStatistician statistician = new LogStatistician(curTime); 44 | statistician.statistic(models); 45 | 46 | // 统计结果入库 47 | bulkRepo.saveAll(statistician.getSpanStatisInfos()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/task/ExpiresCleanTask.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.task; 2 | 3 | import com.yirendai.infra.cicada.configure.CicadaWebProps; 4 | import com.yirendai.infra.cicada.repository.SpanStatisInfoRepository; 5 | import com.yirendai.infra.cicada.util.ElasticIndexManager; 6 | 7 | import org.joda.time.DateTime; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.scheduling.annotation.Scheduled; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * 清除过期数据,包括ES中的原始数据和mysql中的统计数据. 14 | * @author Zecheng 15 | */ 16 | @Component 17 | public class ExpiresCleanTask { 18 | @Autowired 19 | private CicadaWebProps props; 20 | 21 | @Autowired 22 | private ElasticIndexManager esIdxMgr; 23 | 24 | @Autowired 25 | private SpanStatisInfoRepository spanStatisRepo; 26 | 27 | @Scheduled(cron = "0 10 0 * * *") 28 | public void run() { 29 | esIdxMgr.removeExpireIndice(); 30 | final DateTime expireTime = DateTime.now().minusDays(props.getEsIndexRetentionDays()); 31 | spanStatisRepo.cleanExpireInfos(expireTime); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/util/ElasticIndexManager.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util; 2 | 3 | import com.yirendai.infra.cicada.configure.CicadaWebProps; 4 | import com.yirendai.infra.cicada.constants.DateTimeFormats; 5 | 6 | import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; 7 | import org.elasticsearch.action.admin.indices.get.GetIndexRequest; 8 | import org.elasticsearch.action.admin.indices.get.GetIndexResponse; 9 | import org.elasticsearch.client.transport.TransportClient; 10 | import org.joda.time.DateTime; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.LinkedList; 15 | import java.util.List; 16 | import java.util.ListIterator; 17 | 18 | @Component 19 | public class ElasticIndexManager { 20 | private static final String INDEX_CAT_CHARS = "_"; 21 | private static final int VALID_INDEX_NAMEARR_LEN = 2; 22 | 23 | @Autowired 24 | private CicadaWebProps props; 25 | 26 | @Autowired 27 | private TransportClient client; 28 | 29 | /** 30 | * 删除elastic search中超过保存期限的索引. 31 | */ 32 | public void removeExpireIndice() { 33 | final List expireIndice = getExpireIndice(); 34 | for (final String index : expireIndice) { 35 | client.admin().indices().delete(new DeleteIndexRequest(index)).actionGet(); 36 | } 37 | } 38 | 39 | private List getExpireIndice() { 40 | final List allIndice = getAllIndice(); 41 | final long expireTimestamp = DateTime.now().minusDays(props.getEsIndexRetentionDays() + 1).getMillis(); 42 | 43 | final ListIterator iter = allIndice.listIterator(); 44 | while (iter.hasNext()) { 45 | final String indexName = iter.next(); 46 | final String[] nameArr = indexName.split(INDEX_CAT_CHARS); 47 | if (nameArr.length != VALID_INDEX_NAMEARR_LEN) { 48 | iter.remove(); 49 | continue; 50 | } 51 | 52 | final long createTimestamp = DateTime.parse(nameArr[1], // 53 | DateTimeFormats.FULL_DATE_ENGLISH_FORMATTER).getMillis(); 54 | if (createTimestamp >= expireTimestamp) { 55 | iter.remove(); 56 | } 57 | } 58 | 59 | return allIndice; 60 | } 61 | 62 | private List getAllIndice() { 63 | final List indice = new LinkedList(); 64 | final GetIndexResponse resp = client.admin().indices().getIndex(new GetIndexRequest()).actionGet(); 65 | 66 | for (final String indexName : resp.indices()) { 67 | if (indexName.startsWith(props.getEsSpanIndexPrefix()) // 68 | || indexName.startsWith(props.getEsAnnotationIndexPrefix())) { 69 | indice.add(indexName); 70 | } 71 | } 72 | 73 | return indice; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/util/Messages.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util; 2 | 3 | import com.yirendai.infra.cicada.constants.AppError; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.MessageSource; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Locale; 10 | 11 | @Component 12 | public class Messages { 13 | 14 | @Autowired 15 | MessageSource messageSource; 16 | 17 | public String get(final String code) { 18 | return this.get(code, Locale.getDefault(), new String[] {}); 19 | } 20 | 21 | public String get(final String code, final String arg) { 22 | return this.get(code, Locale.getDefault(), new String[] {arg}); 23 | } 24 | 25 | public String get(final String code, final String... args) { 26 | return this.get(code, Locale.getDefault(), args); 27 | } 28 | 29 | public String get(final String code, final Locale locale, final String... args) { 30 | return messageSource.getMessage(code, args, locale); 31 | } 32 | 33 | public String get(final AppError appError, final String... args) { 34 | return this.get(appError.getMessageKey(), Locale.getDefault(), args); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /cicada-web/src/main/java/com/yirendai/infra/cicada/util/ZookeeperUtil.java: -------------------------------------------------------------------------------- 1 | package com.yirendai.infra.cicada.util; 2 | 3 | import lombok.SneakyThrows; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import org.apache.curator.RetryPolicy; 7 | import org.apache.curator.framework.CuratorFramework; 8 | import org.apache.curator.framework.CuratorFrameworkFactory; 9 | import org.apache.curator.retry.ExponentialBackoffRetry; 10 | import org.apache.zookeeper.CreateMode; 11 | import org.apache.zookeeper.KeeperException.NodeExistsException; 12 | import org.apache.zookeeper.data.Stat; 13 | 14 | @Slf4j 15 | public class ZookeeperUtil { 16 | private static final int SESSION_TIMEOUT_MILLIS = 5000; 17 | private static final int CONNECT_TIMEOUT_MILLIS = 3000; 18 | 19 | public static CuratorFramework getClient(final String addr) { 20 | 21 | final RetryPolicy policy = new ExponentialBackoffRetry(1000, 3); 22 | return CuratorFrameworkFactory.builder() // 23 | .connectString(addr) // 24 | .sessionTimeoutMs(SESSION_TIMEOUT_MILLIS) // 25 | .connectionTimeoutMs(CONNECT_TIMEOUT_MILLIS) // 26 | .retryPolicy(policy) // 27 | .build(); 28 | } 29 | 30 | public static CuratorFramework getClient(final String addr, final String namespace) { 31 | final RetryPolicy policy = new ExponentialBackoffRetry(1000, 3); 32 | return CuratorFrameworkFactory.builder() // 33 | .connectString(addr) // 34 | .sessionTimeoutMs(SESSION_TIMEOUT_MILLIS) // 35 | .connectionTimeoutMs(CONNECT_TIMEOUT_MILLIS) // 36 | .retryPolicy(policy) // 37 | .namespace(namespace).build(); 38 | } 39 | 40 | /** 41 | * check if znode exists. 42 | */ 43 | @SneakyThrows 44 | public static boolean exists(final CuratorFramework client, final String path) { 45 | boolean exists = false; 46 | try { 47 | final Stat stat = client.checkExists().forPath(path); 48 | exists = stat != null; 49 | } catch (Exception ex) { 50 | log.error("failed check stat of path: {}, error: {}", path, ex); 51 | throw ex; 52 | } 53 | 54 | return exists; 55 | } 56 | 57 | /** 58 | * this will create the given ZNode with the given data. 59 | */ 60 | @SneakyThrows 61 | public static void create(final CuratorFramework client, final String path, final String content) { 62 | try { 63 | if (content == null) { 64 | client.create().creatingParentsIfNeeded().forPath(path); 65 | } else { 66 | client.create().creatingParentsIfNeeded().forPath(path, content.getBytes()); 67 | } 68 | } catch (NodeExistsException ex) { 69 | log.warn("node exists, can not create it again!"); 70 | } catch (Exception ex) { 71 | log.error("failed create znode: {}, error: {}", path, ex); 72 | throw ex; 73 | } 74 | } 75 | 76 | /** 77 | * this will create the given EPHEMERAL ZNode with the given data. 78 | */ 79 | @SneakyThrows 80 | public static void createEphemeral(final CuratorFramework client, final String path, final String content) { 81 | try { 82 | if (content == null) { 83 | client.create().withMode(CreateMode.EPHEMERAL).forPath(path); 84 | } else { 85 | client.create().withMode(CreateMode.EPHEMERAL).forPath(path, content.getBytes()); 86 | } 87 | } catch (NodeExistsException ex) { 88 | log.warn("node exists, can not create it again!"); 89 | } catch (Exception ex) { 90 | log.error("failed create EPHEMERAL znode: {}, error: {}", path, ex); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /cicada-web/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9880 3 | 4 | spring: 5 | profiles.active: env_development 6 | jpa: 7 | database: mysql 8 | properties.jadira.usertype.autoRegisterUserTypes: true 9 | generate-ddl: false 10 | hibernate.ddl-auto: none 11 | hibernate.naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy 12 | datasource: 13 | driverClassName: com.p6spy.engine.spy.P6SpyDriver 14 | max-active: 50 15 | initial-size: 32 16 | max-idle: 40 17 | min-idle: 1 18 | test-while-idle: true 19 | test-on-borrow: true 20 | validation-query: SELECT 1 21 | time-between-eviction-runs-millis: 5000 22 | min-evictable-idle-time-millis: 60000 23 | 24 | job.slot.range: 65536 25 | 26 | --- 27 | spring: 28 | profiles: env_development 29 | datasource: 30 | url: jdbc:p6spy:mysql://127.0.0.1:3306/cicada?useUnicode=true&characterEncoding=UTF-8 31 | username: cicada 32 | password: dev_cicada_passwd 33 | platform: mysql 34 | 35 | elasticsearch: 36 | node: 37 | addr: 127.0.0.1 38 | port: 9300 39 | cluster.name: cicada_warehouse 40 | bulk.await.minutes: 10 41 | index: 42 | retention.day: 15 43 | type.name: details 44 | span.prefix: cicada-span 45 | annotation.prefix: cicada-annotation 46 | 47 | statistic: 48 | zookeeper: 49 | connection: 127.0.0.1:2181 50 | namespace: infra/cicada 51 | node: 52 | job: /job 53 | master: /master 54 | instances: /instances 55 | 56 | --- 57 | spring: 58 | profiles: env_production 59 | datasource: 60 | platform: mysql 61 | url: jdbc:p6spy:mysql://localhost:3306/cicada?useUnicode=true&characterEncoding=UTF-8 62 | username: cicada 63 | password: prod_cicada_passwd 64 | 65 | elasticsearch: 66 | cluster.name: cicada_warehouse 67 | bulk.await.minutes: 10 68 | node: 69 | addr: 127.0.0.1 70 | port: 9300 71 | index: 72 | retention.day: 15 73 | type.name: details 74 | span.prefix: cicada-span 75 | annotation.prefix: cicada-annotation 76 | 77 | statistic: 78 | zookeeper: 79 | connection: 127.0.0.1:2181 80 | namespace: infra/cicada 81 | node: 82 | job: /job 83 | master: /master 84 | instances: /instances 85 | -------------------------------------------------------------------------------- /cicada-web/src/main/resources/spy.properties: -------------------------------------------------------------------------------- 1 | driverlist=com.mysql.jdbc.Driver,org.h2.Driver 2 | appender=com.p6spy.engine.spy.appender.Slf4JLogger 3 | useprefix=false 4 | deregisterdrivers=true 5 | excludecategories=info,debug,result,resultset,batch,commit 6 | databaseDialectDateFormat=yyyy-MM-dd 7 | filter=true 8 | exclude=SELECT 1 9 | dateformat=yyyy-MM-dd HH:mm:ss:SS -------------------------------------------------------------------------------- /cicada-web/src/main/resources/sql/init.sql: -------------------------------------------------------------------------------- 1 | use infra_cicada_web; 2 | CREATE TABLE `span_statis_info` ( 3 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 4 | `app_id` int(11) NOT NULL, 5 | `avg_duration` double NOT NULL, 6 | `count` bigint(20) NOT NULL, 7 | `failure_rate` double NOT NULL, 8 | `line95duration` int(11) NOT NULL, 9 | `line999duration` int(11) NOT NULL, 10 | `max_duration` int(11) NOT NULL, 11 | `method_id` int(11) NOT NULL, 12 | `min_duration` int(11) NOT NULL, 13 | `service_id` int(11) NOT NULL, 14 | `statis_time` datetime DEFAULT NULL, 15 | PRIMARY KEY (`id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 17 | 18 | 19 | CREATE TABLE `trace_statis_info` ( 20 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 21 | `app_id` int(11) NOT NULL, 22 | `avg_duration` double NOT NULL, 23 | `count` bigint(20) NOT NULL, 24 | `failure_rate` double NOT NULL, 25 | `line95duration` int(11) NOT NULL, 26 | `line999duration` int(11) NOT NULL, 27 | `max_duration` int(11) NOT NULL, 28 | `method_id` int(11) NOT NULL, 29 | `min_duration` int(11) NOT NULL, 30 | `service_id` int(11) NOT NULL, 31 | `statis_time` datetime DEFAULT NULL, 32 | PRIMARY KEY (`id`) 33 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 34 | -------------------------------------------------------------------------------- /cicada-web/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /cicada-web/src/test/resources/spy.properties: -------------------------------------------------------------------------------- 1 | driverlist=com.mysql.jdbc.Driver,org.h2.Driver 2 | appender=com.p6spy.engine.spy.appender.Slf4JLogger 3 | useprefix=false 4 | deregisterdrivers=true 5 | excludecategories=info,debug,result,resultset,batch,commit 6 | databaseDialectDateFormat=yyyy-MM-dd 7 | filter=true 8 | exclude=SELECT 1 9 | dateformat=yyyy-MM-dd HH:mm:ss:SS -------------------------------------------------------------------------------- /scripts/collector_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ACTIVE_PROFILE=env_development # env_development, env_production 4 | VERSION=2.0.1 5 | PACKAGE_NAME=cicada-collector 6 | 7 | function stop() { 8 | pid=`ps -ef | grep $PACKAGE_NAME-$VERSION | grep -v "grep" | awk '{print $2}'` 9 | kill -9 $pid 10 | echo "killed process: $pid" 11 | } 12 | 13 | function start() { 14 | nohup java -jar -Xmx4096M -XX:MaxPermSize=512M \ 15 | -Djava.security.egd=file:/dev/./urandom ${PACKAGE_NAME}-${VERSION}.jar \ 16 | --spring.profiles.active=$ACTIVE_PROFILE > nohup.log & 17 | } 18 | 19 | function restart() { 20 | stop 21 | start 22 | } 23 | 24 | function status() { 25 | ps -ef | grep $PACKAGE_NAME | grep -v "grep" 26 | } 27 | 28 | case $1 in 29 | start) 30 | start 31 | ;; 32 | 33 | stop) 34 | stop 35 | ;; 36 | 37 | status) 38 | status 39 | ;; 40 | 41 | restart) 42 | restart 43 | ;; 44 | 45 | *) 46 | echo -e "Usage $0 { start | stop | restart | status }" 47 | ;; 48 | esac 49 | 50 | -------------------------------------------------------------------------------- /scripts/init.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `app_info` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT, 3 | `app_name` varchar(255) DEFAULT NULL, 4 | `register_time` datetime DEFAULT NULL, 5 | PRIMARY KEY (`id`), 6 | UNIQUE KEY `app_name` (`app_name`) 7 | ) ENGINE=MyISAM AUTO_INCREMENT=29 DEFAULT CHARSET=utf8; 8 | 9 | CREATE TABLE `service_info` ( 10 | `id` int(11) NOT NULL AUTO_INCREMENT, 11 | `app_id` int(11) DEFAULT NULL, 12 | `register_time` datetime DEFAULT NULL, 13 | `service_name` varchar(255) DEFAULT NULL, 14 | PRIMARY KEY (`id`), 15 | UNIQUE KEY `app_service` (`app_id`,`service_name`) 16 | ) ENGINE=MyISAM AUTO_INCREMENT=48 DEFAULT CHARSET=utf8; 17 | 18 | CREATE TABLE `method_info` ( 19 | `id` int(11) NOT NULL AUTO_INCREMENT, 20 | `method_name` varchar(255) DEFAULT NULL, 21 | `register_time` datetime DEFAULT NULL, 22 | `service_id` int(11) NOT NULL, 23 | PRIMARY KEY (`id`), 24 | UNIQUE KEY `service_method` (`service_id`,`method_name`) 25 | ) ENGINE=MyISAM AUTO_INCREMENT=56 DEFAULT CHARSET=utf8; 26 | 27 | CREATE TABLE `span_statis_info` ( 28 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 29 | `app_id` int(11) NOT NULL, 30 | `avg_duration` double NOT NULL, 31 | `count` bigint(20) NOT NULL, 32 | `failure_rate` double NOT NULL, 33 | `line95duration` int(11) NOT NULL, 34 | `line999duration` int(11) NOT NULL, 35 | `max_duration` int(11) NOT NULL, 36 | `method_id` int(11) NOT NULL, 37 | `min_duration` int(11) NOT NULL, 38 | `service_id` int(11) NOT NULL, 39 | `statis_time` datetime DEFAULT NULL, 40 | PRIMARY KEY (`id`) 41 | ) ENGINE=MyISAM AUTO_INCREMENT=22646 DEFAULT CHARSET=utf8; 42 | -------------------------------------------------------------------------------- /scripts/web_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ACTIVE_PROFILE=env_development # env_development, env_production 4 | VERSION=2.0.1 5 | PACKAGE_NAME=cicada-web 6 | 7 | function stop() { 8 | pid=`ps -ef | grep $PACKAGE_NAME-$VERSION | grep -v "grep" | awk '{print $2}'` 9 | kill -9 $pid 10 | echo "killed process: $pid" 11 | } 12 | 13 | function start() { 14 | nohup java -jar -Xmx4096M -XX:MaxPermSize=512M \ 15 | -Djava.security.egd=file:/dev/./urandom ${PACKAGE_NAME}-${VERSION}.jar \ 16 | --spring.profiles.active=$ACTIVE_PROFILE > nohup.log & 17 | } 18 | 19 | function restart() { 20 | stop 21 | start 22 | } 23 | 24 | function status() { 25 | ps -ef | grep $PACKAGE_NAME | grep -v "grep" 26 | } 27 | 28 | case $1 in 29 | start) 30 | start 31 | ;; 32 | 33 | stop) 34 | stop 35 | ;; 36 | 37 | status) 38 | status 39 | ;; 40 | 41 | restart) 42 | restart 43 | ;; 44 | 45 | *) 46 | echo -e "Usage $0 { start | stop | restart | status }" 47 | ;; 48 | esac 49 | 50 | --------------------------------------------------------------------------------