├── .gitignore ├── .idea ├── $PROJECT_FILE$ ├── compiler.xml ├── dictionaries │ └── wangji.xml ├── encodings.xml ├── inspectionProfiles │ └── Project_Default.xml ├── libraries │ ├── Maven__ch_qos_logback_logback_classic_1_2_3.xml │ ├── Maven__ch_qos_logback_logback_core_1_2_3.xml │ ├── Maven__com_aliyun_alibaba_dingtalk_service_sdk_1_0_1.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_annotations_2_11_4.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_core_2_11_4.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_databind_2_11_4.xml │ ├── Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_11_4.xml │ ├── Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_11_4.xml │ ├── Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_11_4.xml │ ├── Maven__com_google_code_findbugs_jsr305_3_0_2.xml │ ├── Maven__com_google_errorprone_error_prone_annotations_2_5_1.xml │ ├── Maven__com_google_guava_failureaccess_1_0_1.xml │ ├── Maven__com_google_guava_guava_30_1_1_jre.xml │ ├── Maven__com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava.xml │ ├── Maven__com_google_j2objc_j2objc_annotations_1_3.xml │ ├── Maven__com_jayway_jsonpath_json_path_2_4_0.xml │ ├── Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml │ ├── Maven__commons_logging_commons_logging_1_1_1.xml │ ├── Maven__io_micrometer_micrometer_core_1_6_6.xml │ ├── Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml │ ├── Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml │ ├── Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml │ ├── Maven__javax_activation_activation_1_1.xml │ ├── Maven__javax_jms_jms_1_1.xml │ ├── Maven__javax_mail_mail_1_4.xml │ ├── Maven__log4j_log4j_1_2_15.xml │ ├── Maven__net_bytebuddy_byte_buddy_1_10_22.xml │ ├── Maven__net_bytebuddy_byte_buddy_agent_1_10_22.xml │ ├── Maven__net_minidev_accessors_smart_1_2.xml │ ├── Maven__net_minidev_json_smart_2_3.xml │ ├── Maven__org_apache_logging_log4j_log4j_api_2_13_3.xml │ ├── Maven__org_apache_logging_log4j_log4j_to_slf4j_2_13_3.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_45.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_45.xml │ ├── Maven__org_apiguardian_apiguardian_api_1_1_0.xml │ ├── Maven__org_assertj_assertj_core_3_18_1.xml │ ├── Maven__org_checkerframework_checker_qual_3_8_0.xml │ ├── Maven__org_codehaus_janino_commons_compiler_3_1_3.xml │ ├── Maven__org_codehaus_janino_janino_3_1_3.xml │ ├── Maven__org_glassfish_jakarta_el_3_0_3.xml │ ├── Maven__org_hamcrest_hamcrest_2_2.xml │ ├── Maven__org_hdrhistogram_HdrHistogram_2_1_12.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_5_7_1.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_api_5_7_1.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_engine_5_7_1.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_params_5_7_1.xml │ ├── Maven__org_junit_platform_junit_platform_commons_1_7_1.xml │ ├── Maven__org_junit_platform_junit_platform_engine_1_7_1.xml │ ├── Maven__org_latencyutils_LatencyUtils_2_0_3.xml │ ├── Maven__org_mockito_mockito_core_3_6_28.xml │ ├── Maven__org_mockito_mockito_junit_jupiter_3_6_28.xml │ ├── Maven__org_objenesis_objenesis_3_1.xml │ ├── Maven__org_opentest4j_opentest4j_1_2_0.xml │ ├── Maven__org_ow2_asm_asm_5_0_4.xml │ ├── Maven__org_projectlombok_lombok_1_18_20.xml │ ├── Maven__org_skyscreamer_jsonassert_1_5_0.xml │ ├── Maven__org_slf4j_jul_to_slf4j_1_7_30.xml │ ├── Maven__org_slf4j_slf4j_api_1_7_30.xml │ ├── Maven__org_springframework_boot_spring_boot_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_actuator_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_actuator_autoconfigure_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_autoconfigure_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_configuration_processor_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_devtools_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_actuator_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_json_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_logging_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_test_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_tomcat_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_web_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_test_2_4_5.xml │ ├── Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_4_5.xml │ ├── Maven__org_springframework_spring_aop_5_3_6.xml │ ├── Maven__org_springframework_spring_beans_5_3_6.xml │ ├── Maven__org_springframework_spring_context_5_3_6.xml │ ├── Maven__org_springframework_spring_core_5_3_6.xml │ ├── Maven__org_springframework_spring_expression_5_3_6.xml │ ├── Maven__org_springframework_spring_jcl_5_3_6.xml │ ├── Maven__org_springframework_spring_test_5_3_6.xml │ ├── Maven__org_springframework_spring_web_5_3_6.xml │ ├── Maven__org_springframework_spring_webmvc_5_3_6.xml │ ├── Maven__org_xmlunit_xmlunit_core_2_7_0.xml │ └── Maven__org_yaml_snakeyaml_1_27.xml ├── misc.xml ├── modules.xml ├── qaplug_profiles.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LOGBACK_README.md ├── README.md ├── dingtalk-robot-logback-demo ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── wangji92 │ │ │ └── logbackappenddemo │ │ │ ├── DingtalkRobotLogbackDemoApplication.java │ │ │ └── controller │ │ │ └── TestController.java │ └── resources │ │ ├── application.properties │ │ ├── logback-dingtalk-better.xml │ │ ├── logback-dingtalk-custom-layout-append.xml │ │ ├── logback-dingtalk-pattern-layout-append.xml │ │ ├── logback-spring-autoconfig-dingtalk.xml │ │ └── logback-spring-help-memory.xml │ └── test │ └── java │ └── com │ └── github │ └── wangji92 │ └── logbackappenddemo │ └── DingtalkRobotLogbackDemoApplicationTests.java ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── github │ │ └── wangji92 │ │ └── dingtalkrobot │ │ ├── DingTalkRobotAppendAutoConfiguration.java │ │ ├── DingTalkRobotAppendProperties.java │ │ ├── core │ │ ├── DingTalkRobotAppendBuilder.java │ │ ├── DingTalkRobotLogbackAppendBootstrap.java │ │ └── DingTalkRobotSender.java │ │ ├── logback │ │ ├── append │ │ │ └── DingTalkRobotAppend.java │ │ ├── layout │ │ │ └── DingTalkRobotLayout.java │ │ ├── listener │ │ │ └── LoggerStartupListener.java │ │ ├── pattern │ │ │ └── CenterBracketsTemplateConverter.java │ │ └── property │ │ │ └── LocalIpDefiner.java │ │ └── utils │ │ └── IpUtils.java └── resources │ ├── META-INF │ └── spring.factories │ ├── com │ └── github │ │ └── wangji92 │ │ └── dingtalkrobot │ │ ├── logback-dingtalk-robot-base.xml │ │ ├── logback-dingtalk-robot-custom-layout.xml │ │ └── logback-dingtalk-robot-pattern-layout.xml │ └── example │ └── logback-dingtalk-robot-example.xml └── test └── java └── com └── github └── wangji92 └── dingtalkrobot └── DingtalkRobotLogbackAlarmSpringBootStartApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | *.idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /.idea/$PROJECT_FILE$: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/dictionaries/wangji.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dingtalk 5 | dingtalkrobot 6 | janino 7 | webhook 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 37 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_aliyun_alibaba_dingtalk_service_sdk_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_11_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_11_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_11_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_11_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_11_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_11_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_code_findbugs_jsr305_3_0_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_errorprone_error_prone_annotations_2_5_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_guava_failureaccess_1_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_guava_guava_30_1_1_jre.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_guava_listenablefuture_9999_0_empty_to_avoid_conflict_with_guava.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_google_j2objc_j2objc_annotations_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_4_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_logging_commons_logging_1_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__io_micrometer_micrometer_core_1_6_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_activation_activation_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_jms_jms_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_mail_mail_1_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__log4j_log4j_1_2_15.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_22.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_22.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_minidev_accessors_smart_1_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_minidev_json_smart_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_13_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_13_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_45.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_45.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_assertj_assertj_core_3_18_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_checkerframework_checker_qual_3_8_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_codehaus_janino_commons_compiler_3_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_codehaus_janino_janino_3_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_glassfish_jakarta_el_3_0_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_2_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hdrhistogram_HdrHistogram_2_1_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_7_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_7_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_7_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_7_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_7_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_7_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_latencyutils_LatencyUtils_2_0_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mockito_mockito_core_3_6_28.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_6_28.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_objenesis_objenesis_3_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_ow2_asm_asm_5_0_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_projectlombok_lombok_1_18_20.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_actuator_autoconfigure_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_configuration_processor_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_devtools_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_actuator_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_4_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_aop_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_beans_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_context_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_core_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_expression_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_jcl_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_test_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_web_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_webmvc_5_3_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_7_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_yaml_snakeyaml_1_27.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.6"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start/5dab3ad095af371cdd84626eb275a49ced0cf1e3/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /LOGBACK_README.md: -------------------------------------------------------------------------------- 1 | # logback 一些不常用知识点 2 | ## 1、变量使用 3 | ### 1.1 使用变量添加默认值 4 | ```xml 5 | ${xxxLevel:-ERROR} 6 | ``` 7 | ### 1.2 直接自定义变量 8 | 比如:日志需要获取本地的Ip 地址写在pattern 中 可以自己定义变量,比较灵活,比如获取本地Ip 9 | [http://logback.qos.ch/manual/configuration.html#definingPropsOnTheFly](http://logback.qos.ch/manual/configuration.html#definingPropsOnTheFly) 10 | ```java 11 | package ch.qos.logback.core.spi; 12 | 13 | public interface PropertyDefiner extends ContextAware { 14 | 15 | /** 16 | * Get the property value, defined by this property definer 17 | * 18 | * @return defined property value 19 | */ 20 | String getPropertyValue(); 21 | } 22 | ``` 23 | ```xml 24 | 25 | 26 | 27 | round 28 | brown 29 | 24 30 | 31 | 32 | 33 | 34 | ``` 35 | ### 1.3 直接使用系统变量 36 | eg 比如要获取 env | hostname, HOME 等等环境变量直接当前属性使用 37 | ```xml 38 | ${HOME}%n ${hostname}%n 39 | ``` 40 | 41 | ### 1.4 直接定义属性不需要编码获取 42 | 43 | ```xml 44 | 45 | 46 | 47 | ``` 48 | 49 | ## 2、使用表达式 50 | 51 | 52 | 比如说某个过滤器需要在xx条件才使用,比如 线上环境打开这个开关 53 | 需要引入包 54 | ```xml 55 | 56 | org.codehaus.janino 57 | janino 58 | 3.1.3 59 | 60 | ``` 61 | ### if else 62 | [http://logback.qos.ch/manual/configuration.html#conditional](http://logback.qos.ch/manual/configuration.html#conditional) 63 | ```xml 64 | 65 | 66 | 67 | 68 | 69 | 70 | %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger - %msg%n 71 | 72 | 73 | 74 | 75 | 76 | 77 | return formattedMessage.contains("通知"); 78 | 79 | 80 | ACCEPT 81 | 82 | DENY 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | ``` 92 | ### evaluator 93 | 评估表达式 在logback 中大量使用这个表达式 94 | [http://logback.qos.ch/manual/layouts.html#Evaluators](http://logback.qos.ch/manual/layouts.html#Evaluators) 95 | 96 | 97 | xEx{depth, evaluator-1, ..., evaluator-n} 这里学到了一招 可以减少异常的深度,可以根据异常的信息进行判断是否打印 98 | 99 | 100 | eg pattern 变量中年使用 101 | 102 | 103 | [http://logback.qos.ch/manual/layouts.html#ClassicPatternLayout](http://logback.qos.ch/manual/layouts.html#ClassicPatternLayout) 104 | caller 只要满足条件 && 才答应出来 105 | ```xml 106 | 107 | 108 | logger.contains("chapters.layouts") && \ 109 | message.contains("who calls thee") 110 | 111 | 112 | 113 | 114 | 115 | %-4relative [%thread] %-5level - %msg%n %caller{2, DISP_CALLER_EVAL} 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | ``` 125 | ## 3、自定义监听器 126 | 自定义监听器可以实现对于变量的注册、操作logcontext 等等! 有非常多的好处 127 | [http://logback.qos.ch/manual/configuration.html#contextListener](http://logback.qos.ch/manual/configuration.html#contextListener) 128 | ```xml 129 | 130 | 131 | true 132 | 133 | .... 134 | 135 | ``` 136 | ```xml 137 | public interface LoggerContextListener { 138 | 139 | /** 140 | * Some listeners should not be removed when the LoggerContext is 141 | * reset. Such listeners are said to be reset resistant. 142 | * @return whether this listener is reset resistant or not. 143 | */ 144 | boolean isResetResistant(); 145 | 146 | void onStart(LoggerContext context); 147 | 148 | void onReset(LoggerContext context); 149 | 150 | void onStop(LoggerContext context); 151 | 152 | void onLevelChange(Logger logger, Level level); 153 | } 154 | ``` 155 | ## 4、善用include 156 | logback 定义文件一大堆,可以通过include 的方法引入 比如定义框架 可以减少一些重复性的工作、引入即可。 157 | 结合if else 、变量 可以简单的编程都可以。 158 | [http://logback.qos.ch/manual/configuration.html#fileInclusion](http://logback.qos.ch/manual/configuration.html#fileInclusion) 159 | ```xml 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | ``` 171 | ```xml 172 | 173 | 174 | 175 | "%d - %m%n" 176 | 177 | 178 | 179 | ``` 180 | ## 5、自定义转换器 181 | layout 中pattern中定义的转换器 比如thread 、level 你也可以自定义一个转换器去处理 182 | [http://logback.qos.ch/manual/layouts.html#customConversionSpecifier](http://logback.qos.ch/manual/layouts.html#customConversionSpecifier) 183 | ## 6、InvokingJoranConfiguratordirectly 184 | 直接调用启动logback ,比如spring 如何实现的呢? 185 | org.springframework.boot.logging.logback.LogbackLoggingSystem#configureByResourceUrl 186 | 187 | 188 | [http://logback.qos.ch/manual/configuration.html#joranDirectly](http://logback.qos.ch/manual/configuration.html#joranDirectly) 189 | Logback relies on a configuration library called Joran, part of logback-core. Logback's default configuration mechanism invokesJoranConfiguratoron the default configuration file it finds on the class path. If you wish to override logback's default configuration mechanism for whatever reason, you can do so by invokingJoranConfiguratordirectly. The next application,_MyApp3_, invokes JoranConfigurator on a configuration file passed as a parameter. 190 | ## 7、自定义Action 191 | 比如spring 中 192 | [http://logback.qos.ch/manual/onJoran.html#action](http://logback.qos.ch/manual/onJoran.html#action) 193 | 194 | 195 | org.springframework.boot.logging.logback.SpringProfileAction 196 | org.springframework.boot.logging.logback.SpringPropertyAction 197 | ```xml 198 | 199 | 201 | ``` 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 1、解决什么问题 2 | 基于钉钉机器人的 logback-append-spring-boot-start,可以通过自定义 logback-append 然后通过钉钉机器人的API 推送到钉钉群,解决线下或者线上 针对错误场景的消息推送,方便开发者快速发现问题解决问题,最终的目的是治理日志,减少异常日志,开发环境快速发现错误。 3 | ## 2、效果图 4 | ![image](https://user-images.githubusercontent.com/20874972/115430659-24d87a80-a237-11eb-9e03-7910abf11e42.png) 5 | ![image](https://user-images.githubusercontent.com/20874972/115430762-3a4da480-a237-11eb-8a7f-12611c2a957a.png) 6 | 7 | ## 3、使用 8 | ### 3.1 依赖 9 | #### 3.1.1 外部依赖 10 | ```xml 11 | 30.1.1-jre 12 | 1.0.1 13 | 3.1.3 14 | 15 | 16 | 17 | com.google.guava 18 | guava 19 | ${guava-version} 20 | provided 21 | 22 | 23 | 24 | 25 | com.aliyun 26 | alibaba-dingtalk-service-sdk 27 | ${alibaba-dingtalk-service-sdk-version} 28 | 29 | 30 | 31 | 32 | org.codehaus.janino 33 | janino 34 | ${janino-version} 35 | 36 | 37 | .... logback的一些核心包 引入spring 基本上都有 38 | ``` 39 | #### 3.1.2 start 包 40 | ```xml 41 | 42 | com.github.WangJi92 43 | dingtalk-robot-logback-append-spring-boot-start 44 | 45 | ``` 46 | ### 3.2 相关配置信息 47 | ```properties 48 | # 自动配置打开 手动配置logback xml 引入关闭 49 | spring.dingtalk.logback.append.enable=true 50 | 51 | # 告警 应用相关配置 【应用名称 、当前环境】 52 | spring.dingtalk.logback.append.application-config.application-name=${spring.application.name} 53 | spring.dingtalk.logback.append.application-config.env=测试环境 54 | 55 | ## 日志 通知范围配置 【自动配置必须】 56 | spring.dingtalk.logback.append.log-config.append-logger-names[0]=root 57 | 58 | ## 处理ERROR 日志 【必须配置】 59 | spring.dingtalk.logback.append.log-config.log-level=ERROR 60 | 61 | ## 关键字过滤 两种方式 1、关键字 2、表达式 http://logback.qos.ch/manual/filters.html#EvaluatorFilter 62 | ## 可以都不配置 只处理loglevel 的过滤 63 | 64 | # 【自动配置支持关键字和表达式】 【手动配置仅支持表达式】 65 | #spring.dingtalk.logback.append.log-config.include-log-message-key-words[0]=dingding 66 | #spring.dingtalk.logback.append.log-config.include-log-message-key-words[1]=wangji 67 | spring.dingtalk.logback.append.log-config.kew-word-expression=return formattedMessage.contains("dingding") || formattedMessage.contains("wangji"); 68 | 69 | ## 异步队列的配置 【需要注意队列的长度 可能丢日志】 70 | spring.dingtalk.logback.append.log-config.async-appender-queue-size=256 71 | spring.dingtalk.logback.append.log-config.async-appender-never-block=false 72 | spring.dingtalk.logback.append.log-config.async-appender-include-caller-data=true 73 | 74 | ## 钉钉机器人告警配置 75 | spring.dingtalk.logback.append.robot-config.robot-title=钉钉日志告警 76 | spring.dingtalk.logback.append.robot-config.webhook=https://oapi.dingtalk.com/robot/send?access_token=34b047c35744144f1433eb02fda6125ef850319e280ea4af6fe6e935ed7847df 77 | spring.dingtalk.logback.append.robot-config.sign-secret=SEC5c6533fc0e86b4f89f4dae5b3d7ee7c42c9d968e360915a21d8c4263ce39c9ca 78 | 79 | ## 钉钉告警发送速度限制 1分钟20次 guava 限制一下 1/3.5 ~=0.2875 80 | spring.dingtalk.logback.append.robot-config.rate-limiter-permits-per-second=0.2875 81 | 82 | # 钉钉通知 快捷链接配置 83 | spring.dingtalk.logback.append.quick-link-config.click-description=点击查看详情 84 | 85 | ## 链接地址支持配置各种变量[localIp]、[hostname] 等等 https://kaifa.baidu.com/searchPage?w=[localIp] 86 | ## 发现问题一键进入服务器、k8s集群的链接地址 87 | ## localIp 为logback 中定义的属性 目前已经有了 hostname、localIp、app 等等关键字 88 | ## 发现问题一键进入服务器、k8s集群的链接地址 89 | spring.dingtalk.logback.append.quick-link-config.click-url=https://kaifa.baidu.com/searchPage?w=[localIp] 90 | 91 | ``` 92 | 93 | ### 3.3 自动装配 94 | 自动装配模式 不需要配置logback的xml通过编程的方式植入钉钉append。 95 | 如下为自动配置特有属性 96 | 97 | ```properties 98 | # 自动配置打开 手动配置logback xml 引入关闭 99 | spring.dingtalk.logback.append.enable=true 100 | ## 日志 通知范围配置 【自动配置必须】 101 | spring.dingtalk.logback.append.log-config.append-logger-names[0]=root 102 | 103 | ## 关键字过滤 两种方式 1、关键字 2、表达式 http://logback.qos.ch/manual/filters.html#EvaluatorFilter 104 | ## 可以都不配置 只处理loglevel 的过滤 105 | # 【自动配置支持关键字和表达式】 【手动配置仅支持表达式】 106 | #spring.dingtalk.logback.append.log-config.log-key-words[0]=dingding 107 | #spring.dingtalk.logback.append.log-config.log-key-words[1]=wangji 108 | spring.dingtalk.logback.append.log-config.kew-word-expression=return formattedMessage.contains("dingding") || formattedMessage.contains("wangji"); 109 | 110 | ``` 111 | 如何理解 append-logger-names 就是将钉钉日志 添加到具体的哪个logger 中去 112 | ```java 113 | private void addLoggerNameDingTalkRobotAppender(AsyncAppender asyncAppender) { 114 | DingTalkRobotAppendProperties.LogConfig logConfig = dingTalkRobotAppendProperties.getLogConfig(); 115 | for (String loggerName : logConfig.getAppendLoggerNames()) { 116 | Logger logger = loggerContext.getLogger(loggerName); 117 | if (logger == null) { 118 | log.warn("dingtalk alarm logger name ={} not found", loggerName); 119 | continue; 120 | } 121 | logger.addAppender(asyncAppender); 122 | } 123 | } 124 | ``` 125 | 126 | 127 | ### 3.3 手动配置xml 128 | * [com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-base.xml](https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start/blob/master/src/main/resources/com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-base.xml) 129 | 130 | 这个是基础配置的属性logback 中使用, spring 扩展logback 提供的 springProperty 标签注入logback 属性 131 | 先引入基础 然后引入具体的 layout ,可以在中间 修改基础引入的属性 比如 DINGTALK_ROBOT_LOG_PATTERN 这个属性 修改一下 ch.qos.logback.classic.encoder.PatternLayoutEncoder 132 | 中使用的日志的模板,使用 CBT_CONVERT_DINGTALK_ROBOT_LOG_PATTERN 进行替换。 133 | 134 | * [spring profile-specific-configuration](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#profile-specific-configuration) 135 | * [org/springframework/boot/logging/logback/defaults.xml](https://github.com/spring-projects/spring-boot/blob/v2.4.5/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml) 136 | 137 | 138 | ```xml 139 | 141 | ``` 142 | 143 | #### 3.3.1 pattern layout 定义的格式 144 | [com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-pattern-layout.xml](https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start/blob/master/src/main/resources/com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-pattern-layout.xml) 145 | ```xml 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | ${CONSOLE_LOG_PATTERN} 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | ``` 176 | #### 3.3.2 手动编程定义的格式 [学习自己玩一下] 177 | 178 | [com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-custom-layout.xml](https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start/blob/master/src/main/resources/com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-custom-layout.xml) 179 | 180 | com.github.wangji92.dingtalkrobot.logback.layout.DingTalkRobotLayout 181 | ```xml 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | ${CONSOLE_LOG_PATTERN} 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | ``` 211 | ### 4、logback 的一些 学习 212 | 213 | [logback append 开发过程中了解的总结](LOGBACK_README.md) 214 | 215 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.6"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start/5dab3ad095af371cdd84626eb275a49ced0cf1e3/dingtalk-robot-logback-demo/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.5 9 | 10 | 11 | com.github.WangJi92 12 | dingtalk-robot-logback-demo 13 | 0.0.1-SNAPSHOT 14 | dingtalk-robot-logback-demo 15 | 钉钉告警demo 16 | 17 | 1.8 18 | 30.1.1-jre 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-devtools 29 | runtime 30 | true 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-configuration-processor 35 | true 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | true 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | com.google.guava 49 | guava 50 | ${guava-version} 51 | provided 52 | 53 | 54 | com.github.WangJi92 55 | dingtalk-robot-logback-append-spring-boot-start 56 | 0.0.5 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-actuator 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-maven-plugin 69 | 70 | 71 | 72 | org.projectlombok 73 | lombok 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/java/com/github/wangji92/logbackappenddemo/DingtalkRobotLogbackDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.logbackappenddemo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author 汪小哥 8 | */ 9 | @SpringBootApplication 10 | public class DingtalkRobotLogbackDemoApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(DingtalkRobotLogbackDemoApplication.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/java/com/github/wangji92/logbackappenddemo/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.logbackappenddemo.controller; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.slf4j.MDC; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | /** 11 | * 模拟服务不正常 12 | * 13 | * @author 汪小哥 14 | * @date 02-04-2021 15 | */ 16 | @RestController 17 | @Slf4j 18 | public class TestController { 19 | 20 | /** 21 | * 打印日志 22 | * 23 | * @param message 24 | * @return 25 | */ 26 | @GetMapping("/logError") 27 | public ResponseEntity logError(@RequestParam(required = false) String message) { 28 | MDC.put("testMdc", "testMdc"); 29 | MDC.put("testMdc2", "testMdc2"); 30 | try { 31 | doException(); 32 | } catch (Exception e) { 33 | log.error("exception {}", message, e); 34 | } 35 | return ResponseEntity.ok(200); 36 | } 37 | 38 | int doException() { 39 | int a = 1 / 0; 40 | return a; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # \u914D\u7F6E \u8D70\u54EA\u4E2A logback xml 2 | 3 | #logging.config=classpath:logback-dingtalk-better.xml 4 | #logging.config=classpath:logback-dingtalk-custom-layout-append.xml 5 | #logging.config=classpath:logback-dingtalk-pattern-layout-append.xml 6 | 7 | #\u81EA\u52A8\u88C5\u914D spring.dingtalk.logback.append.enable=true \u4E0D\u9700\u8981\u914D\u7F6Exml 8 | logging.config=classpath:logback-spring-autoconfig-dingtalk.xml 9 | 10 | #\u7F16\u7801\u65B9\u5F0F \u4E0D\u7136\u4E71\u7801 11 | logging.charset.console=UTF-8 12 | 13 | spring.application.name=logback demo 14 | 15 | # \u81EA\u52A8\u914D\u7F6E\u5173\u95ED \u8D70xml 16 | spring.dingtalk.logback.append.enable=true 17 | # \u544A\u8B66 \u5E94\u7528\u76F8\u5173\u914D\u7F6E 18 | spring.dingtalk.logback.append.application-config.application-name=${spring.application.name} 19 | spring.dingtalk.logback.append.application-config.env=\u6D4B\u8BD5\u73AF\u5883 20 | 21 | ## \u65E5\u5FD7 \u901A\u77E5\u8303\u56F4\u914D\u7F6E 22 | spring.dingtalk.logback.append.log-config.append-logger-names[0]=root 23 | 24 | spring.dingtalk.logback.append.log-config.log-level=ERROR 25 | #spring.dingtalk.logback.append.log-config.include-log-message-key-words=dingding 26 | #spring.dingtalk.logback.append.log-config.include-log-message-key-words=wangji 27 | 28 | spring.dingtalk.logback.append.log-config.kew-word-expression=return formattedMessage.contains("dingding") || formattedMessage.contains("wangji"); 29 | spring.dingtalk.logback.append.log-config.async-appender-queue-size=10 30 | spring.dingtalk.logback.append.log-config.async-appender-never-block=false 31 | spring.dingtalk.logback.append.log-config.async-appender-include-caller-data=true 32 | 33 | ## \u9489\u9489\u673A\u5668\u4EBA\u544A\u8B66\u914D\u7F6E 34 | spring.dingtalk.logback.append.robot-config.robot-title=\u9489\u9489\u65E5\u5FD7\u544A\u8B66 35 | spring.dingtalk.logback.append.robot-config.webhook=https://oapi.dingtalk.com/robot/send?access_token=34b047c35744144f1433eb02fda6125ef850319e280ea4af6fe6e935ed7847df 36 | spring.dingtalk.logback.append.robot-config.sign-secret=SEC5c6533fc0e86b4f89f4dae5b3d7ee7c42c9d968e360915a21d8c4263ce39c9ca 37 | spring.dingtalk.logback.append.robot-config.rate-limiter-permits-per-second=0.2875 38 | 39 | # \u9489\u9489\u901A\u77E5 \u5FEB\u6377\u94FE\u63A5\u914D\u7F6E 40 | spring.dingtalk.logback.append.quick-link-config.click-description=\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5 41 | spring.dingtalk.logback.append.quick-link-config.click-url=https://kaifa.baidu.com/searchPage?w=[localIp] 42 | 43 | 44 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/resources/logback-dingtalk-better.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ${CONSOLE_LOG_PATTERN} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/resources/logback-dingtalk-custom-layout-append.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ${CONSOLE_LOG_PATTERN} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/resources/logback-dingtalk-pattern-layout-append.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ${CONSOLE_LOG_PATTERN} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/resources/logback-spring-autoconfig-dingtalk.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ${CONSOLE_LOG_PATTERN} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/main/resources/logback-spring-help-memory.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | logback 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | info 28 | 29 | 30 | ${CONSOLE_LOG_PATTERN} 31 | 32 | UTF-8 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ${LOG_FILE}/web_debug.log 41 | 42 | 43 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 44 | UTF-8 45 | 46 | 47 | 48 | 49 | ${LOG_FILE}/web-debug-%d{yyyy-MM-dd}.%i.log 50 | 51 | 100MB 52 | 53 | 54 | 15 55 | 56 | 57 | 58 | debug 59 | ACCEPT 60 | DENY 61 | 62 | 63 | 64 | 65 | 66 | 67 | ${LOG_FILE}/web_info.log 68 | 69 | 70 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 71 | UTF-8 72 | 73 | 74 | 75 | 76 | ${LOG_FILE}/web-info-%d{yyyy-MM-dd}.%i.log 77 | 78 | 100MB 79 | 80 | 81 | 15 82 | 83 | 84 | 85 | info 86 | ACCEPT 87 | DENY 88 | 89 | 90 | 91 | 92 | 93 | 94 | ${LOG_FILE}/web_warn.log 95 | 96 | 97 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 98 | UTF-8 99 | 100 | 101 | 102 | ${LOG_FILE}/web-warn-%d{yyyy-MM-dd}.%i.log 103 | 104 | 100MB 105 | 106 | 107 | 15 108 | 109 | 110 | 111 | warn 112 | ACCEPT 113 | DENY 114 | 115 | 116 | 117 | 118 | 119 | 120 | ${LOG_FILE}/web_error.log 121 | 122 | 123 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 124 | UTF-8 125 | 126 | 127 | 128 | ${LOG_FILE}/web-error-%d{yyyy-MM-dd}.%i.log 129 | 130 | 100MB 131 | 132 | 133 | 15 134 | 135 | 136 | 137 | ERROR 138 | ACCEPT 139 | DENY 140 | 141 | 142 | 143 | 155 | 156 | 162 | 163 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 194 | 195 | -------------------------------------------------------------------------------- /dingtalk-robot-logback-demo/src/test/java/com/github/wangji92/logbackappenddemo/DingtalkRobotLogbackDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.logbackappenddemo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DingtalkRobotLogbackDemoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ]; then 38 | 39 | if [ -f /etc/mavenrc ]; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ]; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false 51 | darwin=false 52 | mingw=false 53 | case "$(uname)" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true ;; 56 | Darwin*) 57 | darwin=true 58 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 59 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 60 | if [ -z "$JAVA_HOME" ]; then 61 | if [ -x "/usr/libexec/java_home" ]; then 62 | export JAVA_HOME="$(/usr/libexec/java_home)" 63 | else 64 | export JAVA_HOME="/Library/Java/Home" 65 | fi 66 | fi 67 | ;; 68 | esac 69 | 70 | if [ -z "$JAVA_HOME" ]; then 71 | if [ -r /etc/gentoo-release ]; then 72 | JAVA_HOME=$(java-config --jre-home) 73 | fi 74 | fi 75 | 76 | if [ -z "$M2_HOME" ]; then 77 | ## resolve links - $0 may be a link to maven's home 78 | PRG="$0" 79 | 80 | # need this for relative symlinks 81 | while [ -h "$PRG" ]; do 82 | ls=$(ls -ld "$PRG") 83 | link=$(expr "$ls" : '.*-> \(.*\)$') 84 | if expr "$link" : '/.*' >/dev/null; then 85 | PRG="$link" 86 | else 87 | PRG="$(dirname "$PRG")/$link" 88 | fi 89 | done 90 | 91 | saveddir=$(pwd) 92 | 93 | M2_HOME=$(dirname "$PRG")/.. 94 | 95 | # make it fully qualified 96 | M2_HOME=$(cd "$M2_HOME" && pwd) 97 | 98 | cd "$saveddir" 99 | # echo Using m2 at $M2_HOME 100 | fi 101 | 102 | # For Cygwin, ensure paths are in UNIX format before anything is touched 103 | if $cygwin; then 104 | [ -n "$M2_HOME" ] && 105 | M2_HOME=$(cygpath --unix "$M2_HOME") 106 | [ -n "$JAVA_HOME" ] && 107 | JAVA_HOME=$(cygpath --unix "$JAVA_HOME") 108 | [ -n "$CLASSPATH" ] && 109 | CLASSPATH=$(cygpath --path --unix "$CLASSPATH") 110 | fi 111 | 112 | # For Mingw, ensure paths are in UNIX format before anything is touched 113 | if $mingw; then 114 | [ -n "$M2_HOME" ] && 115 | M2_HOME="$( ( 116 | cd "$M2_HOME" 117 | pwd 118 | ))" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="$( ( 121 | cd "$JAVA_HOME" 122 | pwd 123 | ))" 124 | fi 125 | 126 | if [ -z "$JAVA_HOME" ]; then 127 | javaExecutable="$(which javac)" 128 | if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then 129 | # readlink(1) is not available as standard on Solaris 10. 130 | readLink=$(which readlink) 131 | if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then 132 | if $darwin; then 133 | javaHome="$(dirname \"$javaExecutable\")" 134 | javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac" 135 | else 136 | javaExecutable="$(readlink -f \"$javaExecutable\")" 137 | fi 138 | javaHome="$(dirname \"$javaExecutable\")" 139 | javaHome=$(expr "$javaHome" : '\(.*\)/bin') 140 | JAVA_HOME="$javaHome" 141 | export JAVA_HOME 142 | fi 143 | fi 144 | fi 145 | 146 | if [ -z "$JAVACMD" ]; then 147 | if [ -n "$JAVA_HOME" ]; then 148 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then 149 | # IBM's JDK on AIX uses strange locations for the executables 150 | JAVACMD="$JAVA_HOME/jre/sh/java" 151 | else 152 | JAVACMD="$JAVA_HOME/bin/java" 153 | fi 154 | else 155 | JAVACMD="$(which java)" 156 | fi 157 | fi 158 | 159 | if [ ! -x "$JAVACMD" ]; then 160 | echo "Error: JAVA_HOME is not defined correctly." >&2 161 | echo " We cannot execute $JAVACMD" >&2 162 | exit 1 163 | fi 164 | 165 | if [ -z "$JAVA_HOME" ]; then 166 | echo "Warning: JAVA_HOME environment variable is not set." 167 | fi 168 | 169 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 170 | 171 | # traverses directory structure from process work directory to filesystem root 172 | # first directory with .mvn subdirectory is considered project base directory 173 | find_maven_basedir() { 174 | 175 | if [ -z "$1" ]; then 176 | echo "Path not specified to find_maven_basedir" 177 | return 1 178 | fi 179 | 180 | basedir="$1" 181 | wdir="$1" 182 | while [ "$wdir" != '/' ]; do 183 | if [ -d "$wdir"/.mvn ]; then 184 | basedir=$wdir 185 | break 186 | fi 187 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 188 | if [ -d "${wdir}" ]; then 189 | wdir=$( 190 | cd "$wdir/.." 191 | pwd 192 | ) 193 | fi 194 | # end of workaround 195 | done 196 | echo "${basedir}" 197 | } 198 | 199 | # concatenates all lines of a file 200 | concat_lines() { 201 | if [ -f "$1" ]; then 202 | echo "$(tr -s '\n' ' ' <"$1")" 203 | fi 204 | } 205 | 206 | BASE_DIR=$(find_maven_basedir "$(pwd)") 207 | if [ -z "$BASE_DIR" ]; then 208 | exit 1 209 | fi 210 | 211 | ########################################################################################## 212 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 213 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 214 | ########################################################################################## 215 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 216 | if [ "$MVNW_VERBOSE" = true ]; then 217 | echo "Found .mvn/wrapper/maven-wrapper.jar" 218 | fi 219 | else 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 222 | fi 223 | if [ -n "$MVNW_REPOURL" ]; then 224 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 225 | else 226 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 227 | fi 228 | while IFS="=" read key value; do 229 | case "$key" in wrapperUrl) 230 | jarUrl="$value" 231 | break 232 | ;; 233 | esac 234 | done <"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 235 | if [ "$MVNW_VERBOSE" = true ]; then 236 | echo "Downloading from: $jarUrl" 237 | fi 238 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 239 | if $cygwin; then 240 | wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") 241 | fi 242 | 243 | if command -v wget >/dev/null; then 244 | if [ "$MVNW_VERBOSE" = true ]; then 245 | echo "Found wget ... using wget" 246 | fi 247 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 248 | wget "$jarUrl" -O "$wrapperJarPath" 249 | else 250 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 251 | fi 252 | elif command -v curl >/dev/null; then 253 | if [ "$MVNW_VERBOSE" = true ]; then 254 | echo "Found curl ... using curl" 255 | fi 256 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 257 | curl -o "$wrapperJarPath" "$jarUrl" -f 258 | else 259 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 260 | fi 261 | 262 | else 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo "Falling back to using Java to download" 265 | fi 266 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 267 | # For Cygwin, switch paths to Windows format before running javac 268 | if $cygwin; then 269 | javaClass=$(cygpath --path --windows "$javaClass") 270 | fi 271 | if [ -e "$javaClass" ]; then 272 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Compiling MavenWrapperDownloader.java ..." 275 | fi 276 | # Compiling the Java class 277 | ("$JAVA_HOME/bin/javac" "$javaClass") 278 | fi 279 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 280 | # Running the downloader 281 | if [ "$MVNW_VERBOSE" = true ]; then 282 | echo " - Running MavenWrapperDownloader.java ..." 283 | fi 284 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 285 | fi 286 | fi 287 | fi 288 | fi 289 | ########################################################################################## 290 | # End of extension 291 | ########################################################################################## 292 | 293 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 294 | if [ "$MVNW_VERBOSE" = true ]; then 295 | echo $MAVEN_PROJECTBASEDIR 296 | fi 297 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 298 | 299 | # For Cygwin, switch paths to Windows format before running java 300 | if $cygwin; then 301 | [ -n "$M2_HOME" ] && 302 | M2_HOME=$(cygpath --path --windows "$M2_HOME") 303 | [ -n "$JAVA_HOME" ] && 304 | JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") 305 | [ -n "$CLASSPATH" ] && 306 | CLASSPATH=$(cygpath --path --windows "$CLASSPATH") 307 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 308 | MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") 309 | fi 310 | 311 | # Provide a "standardized" way to retrieve the CLI args that will 312 | # work with both Windows and non-Windows executions. 313 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 314 | export MAVEN_CMD_LINE_ARGS 315 | 316 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 317 | 318 | exec "$JAVACMD" \ 319 | $MAVEN_OPTS \ 320 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 321 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 322 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 323 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.github.WangJi92 7 | dingtalk-robot-logback-append-spring-boot-start 8 | 0.0.5 9 | dingtalk-robot-logback-append-spring-boot-start 10 | 自定义logback append 将日志 通过钉钉API将日志信息通知到群 11 | https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start 12 | 13 | 1.8 14 | 30.1.1-jre 15 | 1.0.1 16 | 3.1.3 17 | 2.4.5 18 | 19 | 20 | 21 | The Apache Software License, Version 2.0 22 | http://www.apache.org/licenses/LICENSE-2.0.txt 23 | repo 24 | 25 | 26 | 27 | 28 | https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start 29 | https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start.git 30 | https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start.gi 31 | 32 | 33 | 34 | 35 | wangji 36 | 983433479@qq.com 37 | https://github.com/WangJi92/dingtalk-robot-logback-append-spring-boot-start.gi 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-dependencies 45 | ${spring-boot.version} 46 | pom 47 | import 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-devtools 55 | runtime 56 | true 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter 61 | provided 62 | 63 | 64 | org.springframework.boot 65 | spring-boot 66 | provided 67 | 68 | 69 | org.springframework 70 | spring-core 71 | provided 72 | 73 | 74 | org.springframework 75 | spring-context 76 | provided 77 | 78 | 79 | org.springframework.boot 80 | spring-boot-autoconfigure 81 | provided 82 | 83 | 84 | org.springframework.boot 85 | spring-boot-configuration-processor 86 | true 87 | 88 | 89 | org.projectlombok 90 | lombok 91 | true 92 | 93 | 94 | com.google.guava 95 | guava 96 | ${guava-version} 97 | provided 98 | 99 | 100 | com.aliyun 101 | alibaba-dingtalk-service-sdk 102 | ${alibaba-dingtalk-service-sdk-version} 103 | 104 | 105 | org.codehaus.janino 106 | janino 107 | ${janino-version} 108 | 109 | 110 | 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-compiler-plugin 116 | 3.1 117 | 118 | 1.8 119 | 1.8 120 | 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-source-plugin 125 | 3.0.1 126 | 127 | true 128 | 129 | 130 | 131 | compile 132 | 133 | jar 134 | 135 | 136 | 137 | 138 | 139 | org.apache.maven.plugins 140 | maven-javadoc-plugin 141 | 3.0.1 142 | 143 | false 144 | none 145 | 146 | 147 | 148 | package 149 | 150 | jar 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | release 161 | 162 | 163 | oss 164 | https://oss.sonatype.org/content/repositories/snapshots/ 165 | 166 | 167 | oss 168 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 169 | 170 | 171 | 172 | 173 | 174 | 175 | org.apache.maven.plugins 176 | maven-source-plugin 177 | 3.0.1 178 | 179 | 180 | oss 181 | package 182 | 183 | jar-no-fork 184 | 185 | 186 | 187 | 188 | 189 | 190 | org.apache.maven.plugins 191 | maven-gpg-plugin 192 | 1.6 193 | 194 | 195 | oss 196 | verify 197 | 198 | sign 199 | 200 | 201 | 202 | 203 | 204 | org.sonatype.plugins 205 | nexus-staging-maven-plugin 206 | 1.6.8 207 | true 208 | 209 | oss 210 | https://oss.sonatype.org/ 211 | true 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/DingTalkRobotAppendAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot; 2 | 3 | import com.github.wangji92.dingtalkrobot.core.DingTalkRobotLogbackAppendBootstrap; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.ComponentScan; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | /** 12 | * @author 汪小哥 13 | * @date 17-04-2021 14 | */ 15 | @Configuration 16 | @ConditionalOnClass(name = "ch.qos.logback.classic.LoggerContext") 17 | @ConditionalOnProperty(prefix = "spring.dingtalk.logback.append", value = "enable", havingValue = "true", matchIfMissing = true) 18 | @ComponentScan(value = "com.github.wangji92.dingtalkrobot") 19 | @Slf4j 20 | public class DingTalkRobotAppendAutoConfiguration { 21 | 22 | @Bean 23 | public DingTalkRobotLogbackAppendBootstrap dingTalkRobotLogbackAlarmBootstrap() { 24 | return new DingTalkRobotLogbackAppendBootstrap(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/DingTalkRobotAppendProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot; 2 | 3 | import ch.qos.logback.core.AsyncAppenderBase; 4 | import com.github.wangji92.dingtalkrobot.core.DingTalkRobotLogbackAppendBootstrap; 5 | import com.google.common.collect.Lists; 6 | import lombok.Data; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.boot.logging.LogLevel; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * 钉钉告警配置 15 | * 16 | * @author 汪小哥 17 | * @date 17-04-2021 18 | */ 19 | @ConfigurationProperties(prefix = "spring.dingtalk.logback.append") 20 | @Data 21 | @Configuration 22 | public class DingTalkRobotAppendProperties { 23 | /** 24 | * 是否启用 25 | */ 26 | private boolean enable = false; 27 | /** 28 | * 钉钉机器人的配置 29 | */ 30 | private DingTalkRobot robotConfig; 31 | 32 | /** 33 | * 应用配置 34 | */ 35 | private ApplicationConfig applicationConfig; 36 | 37 | /** 38 | * 日志配置 39 | */ 40 | private LogConfig logConfig; 41 | 42 | /** 43 | * 查看详情 44 | */ 45 | private QuickLink quickLinkConfig; 46 | 47 | 48 | @Data 49 | public static class ApplicationConfig { 50 | /** 51 | * 当前环境 not set is Environment=>spring.profiles.active 52 | */ 53 | private String env = ""; 54 | /** 55 | * 应用名称 not set is Environment=>spring.application.name 56 | */ 57 | private String applicationName = ""; 58 | } 59 | 60 | @Data 61 | public static class LogConfig { 62 | /** 63 | * 当前level 等级之上的都打印 64 | */ 65 | private LogLevel logLevel = LogLevel.ERROR; 66 | /** 67 | * 消息中有关键词才钉钉通知 逗号分割 68 | * {@link DingTalkRobotLogbackAppendBootstrap#buildJaninoEvaluatorFilter()} 69 | * 这里使用的表达式 kewWordExpression : return formattedMessage.contains("keyword1") || formattedMessage.contains("keyword2"); 70 | */ 71 | private List includeLogMessageKeyWords; 72 | 73 | /** 74 | * 排除掉message 里面的关键字 不打印 75 | */ 76 | private List excludeLogMessageKeyWords; 77 | 78 | /** 79 | * 哪些日志名称不打印 包含关键字 80 | */ 81 | private List excludeLogName; 82 | 83 | /** 84 | * 消息中过滤 自己定义表达式 和 logKeyWords 冲突 {@literal http://logback.qos.ch/manual/filters.html#EvaluatorFilter} 85 | * return formattedMessage.contains("keyword1") || formattedMessage.contains("keyword12"); 86 | */ 87 | private String kewWordExpression = ""; 88 | 89 | /** 90 | * 添加到哪些 logger name 91 | */ 92 | private List appendLoggerNames = Lists.newArrayList("root"); 93 | 94 | /** 95 | * mdc 里面哪些需要打印 96 | */ 97 | private List mdcList = Lists.newArrayList(); 98 | 99 | /** 100 | * blockingQueue长度决定了队列能放多少信息,在默认的配置下,如果blockingQueue放满了,后续想要输出日志的线程会被阻塞, 101 | * 直到Worker线程处理掉队列中的信息为止。 102 | * 根据实际情况适当调整队列长度,可以防止线程被阻塞。 103 | * {@link DingTalkRobotLogbackAppendBootstrap#buildAsyncAppender()} 104 | */ 105 | private Integer asyncAppenderQueueSize = 256; 106 | 107 | /** 108 | * 这里可能会丢日志 {@link AsyncAppenderBase#put(Object) offer 方法没有足够空间直接扔掉} 109 | * 如果配置neverBlock=true,当队列满了之后,后面阻塞的线程想要输出的消息就直接被丢弃,从而线程不会阻塞。 110 | * 这个配置用于线程很重要,不能卡顿,而且日志又不是很重要的场景,因为很有可能会丢日志 111 | * {@link DingTalkRobotLogbackAppendBootstrap#buildAsyncAppender()} 112 | */ 113 | private Boolean asyncAppenderNeverBlock = true; 114 | 115 | /** 116 | * 提取调用方数据可能相当昂贵。 117 | * 若要提高性能,默认情况下,当事件添加到事件队列时,不会提取与事件关联的调用方数据。 118 | * 默认情况下,只有“廉价”数据,如线程名和 都被复制了。 119 | * {@link DingTalkRobotLogbackAppendBootstrap#buildAsyncAppender()} 120 | */ 121 | private Boolean asyncAppenderIncludeCallerData = true; 122 | } 123 | 124 | /** 125 | * 钉钉的配置 126 | */ 127 | @Data 128 | public static class DingTalkRobot { 129 | /** 130 | * 钉钉机器人配置 webhook 131 | */ 132 | private String webhook; 133 | /** 134 | * 钉钉机器人加签关键字 135 | */ 136 | private String signSecret; 137 | /** 138 | * 钉钉发送消息头 139 | */ 140 | private String robotTitle = "钉钉日志告警通知"; 141 | 142 | /** 143 | * 机器人发送速度限制 [每分钟最多20次] 1/3.5~= 0.2857 144 | */ 145 | private Double rateLimiterPermitsPerSecond = 0.2857; 146 | } 147 | 148 | /** 149 | * 打印的日志追加一个详情 150 | */ 151 | @Data 152 | public static class QuickLink { 153 | /** 154 | * 点击查看详情 155 | */ 156 | private String clickDescription = "点击查看详情"; 157 | /** 158 | * 支持变量 ip 或者 app (应用名称) 159 | * https://kaifa.baidu.com/searchPage?wd=[localIp] or [hostname] or other 属性 160 | */ 161 | private String clickUrl; 162 | } 163 | 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/core/DingTalkRobotAppendBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.core; 2 | 3 | import ch.qos.logback.classic.LoggerContext; 4 | import com.github.wangji92.dingtalkrobot.DingTalkRobotAppendProperties; 5 | import com.github.wangji92.dingtalkrobot.logback.append.DingTalkRobotAppend; 6 | import com.github.wangji92.dingtalkrobot.logback.layout.DingTalkRobotLayout; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.context.ApplicationContext; 9 | import org.springframework.util.Assert; 10 | import org.springframework.util.StringUtils; 11 | 12 | /** 13 | * 初始化构造 DingTalkRobotAppend 14 | * 15 | * @author 汪小哥 16 | * @date 17-04-2021 17 | */ 18 | @Slf4j 19 | public class DingTalkRobotAppendBuilder { 20 | 21 | private static final String HTTP = "http"; 22 | 23 | private DingTalkRobotAppendProperties dingTalkRobotAppendProperties; 24 | 25 | private ApplicationContext applicationContext; 26 | 27 | private LoggerContext loggerContext; 28 | 29 | public DingTalkRobotAppendBuilder(DingTalkRobotAppendProperties dingTalkRobotAppendProperties, ApplicationContext applicationContext) { 30 | this.dingTalkRobotAppendProperties = dingTalkRobotAppendProperties; 31 | this.applicationContext = applicationContext; 32 | } 33 | 34 | /** 35 | * 构建 DingTalkRobotAppend 36 | * 37 | * @return 38 | */ 39 | public DingTalkRobotAppend buildDingTalkRobotAppend() { 40 | this.checkConfig(); 41 | DingTalkRobotAppend dingTalkRobotAppend = new DingTalkRobotAppend(); 42 | DingTalkRobotAppendProperties.DingTalkRobot robot = dingTalkRobotAppendProperties.getRobotConfig(); 43 | dingTalkRobotAppend.setWebhook(robot.getWebhook()); 44 | dingTalkRobotAppend.setSignSecret(robot.getSignSecret()); 45 | dingTalkRobotAppend.setRateLimiterPermitsPerSecond(dingTalkRobotAppendProperties.getRobotConfig().getRateLimiterPermitsPerSecond()); 46 | String title = robot.getRobotTitle(); 47 | if (!StringUtils.hasText(title)) { 48 | title = "钉钉日志告警通知"; 49 | } 50 | dingTalkRobotAppend.setRobotTitle(title); 51 | dingTalkRobotAppend.setContext(loggerContext); 52 | DingTalkRobotLayout layout = this.buildDingTalkRobotLayout(loggerContext, robot); 53 | layout.setMdcList(dingTalkRobotAppendProperties.getLogConfig().getMdcList()); 54 | layout.start(); 55 | dingTalkRobotAppend.setLayout(layout); 56 | dingTalkRobotAppend.start(); 57 | return dingTalkRobotAppend; 58 | } 59 | 60 | 61 | /** 62 | * 检查配置 63 | */ 64 | private void checkConfig() { 65 | Assert.notNull(loggerContext, "logger context must not be null"); 66 | Assert.notNull(dingTalkRobotAppendProperties, "dingtalk dingTalkRobotAppendProperties config must not be null"); 67 | 68 | Assert.notNull(dingTalkRobotAppendProperties.getRobotConfig(), "dingtalk robot config must not be null"); 69 | Assert.hasText(dingTalkRobotAppendProperties.getRobotConfig().getWebhook(), "dingtalk robot config must not be null"); 70 | } 71 | 72 | /** 73 | * 构建 DingTalkRobotLayout 74 | * 75 | * @param loggerContext 76 | * @param robot 77 | * @return 78 | */ 79 | private DingTalkRobotLayout buildDingTalkRobotLayout(LoggerContext loggerContext, DingTalkRobotAppendProperties.DingTalkRobot robot) { 80 | DingTalkRobotLayout layout = new DingTalkRobotLayout(); 81 | layout.setContext(loggerContext); 82 | DingTalkRobotAppendProperties.ApplicationConfig applicationConfig = dingTalkRobotAppendProperties.getApplicationConfig(); 83 | if (applicationConfig == null) { 84 | applicationConfig = new DingTalkRobotAppendProperties.ApplicationConfig(); 85 | } 86 | String env = applicationConfig.getEnv(); 87 | if (!StringUtils.hasText(env)) { 88 | env = applicationContext.getEnvironment().getProperty("spring.profiles.active"); 89 | } 90 | layout.setEnv(env); 91 | String app = applicationConfig.getApplicationName(); 92 | if (!StringUtils.hasText(env)) { 93 | app = applicationContext.getEnvironment().getProperty("spring.application.name"); 94 | } 95 | layout.setApp(app); 96 | 97 | // 快捷链接 方便直接点击进入服务器 98 | DingTalkRobotAppendProperties.QuickLink quickLink = dingTalkRobotAppendProperties.getQuickLinkConfig(); 99 | if (quickLink != null && StringUtils.hasText(quickLink.getClickDescription())) { 100 | layout.setClickDescription(quickLink.getClickDescription()); 101 | if (StringUtils.hasText(quickLink.getClickUrl()) && quickLink.getClickUrl().contains(HTTP)) { 102 | 103 | layout.setClickUrl(quickLink.getClickUrl()); 104 | } 105 | } 106 | return layout; 107 | } 108 | 109 | public DingTalkRobotAppendProperties getDingTalkRobotAppendProperties() { 110 | return dingTalkRobotAppendProperties; 111 | } 112 | 113 | public void setDingTalkRobotAppendProperties(DingTalkRobotAppendProperties dingTalkRobotAppendProperties) { 114 | this.dingTalkRobotAppendProperties = dingTalkRobotAppendProperties; 115 | } 116 | 117 | public ApplicationContext getApplicationContext() { 118 | return applicationContext; 119 | } 120 | 121 | public void setApplicationContext(ApplicationContext applicationContext) { 122 | this.applicationContext = applicationContext; 123 | } 124 | 125 | public LoggerContext getLoggerContext() { 126 | return loggerContext; 127 | } 128 | 129 | public void setLoggerContext(LoggerContext loggerContext) { 130 | this.loggerContext = loggerContext; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/core/DingTalkRobotSender.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.core; 2 | 3 | import com.dingtalk.api.DefaultDingTalkClient; 4 | import com.dingtalk.api.DingTalkClient; 5 | import com.dingtalk.api.request.OapiRobotSendRequest; 6 | import com.dingtalk.api.response.OapiRobotSendResponse; 7 | import com.google.common.util.concurrent.RateLimiter; 8 | import com.taobao.api.ApiException; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.util.StringUtils; 11 | 12 | import javax.crypto.Mac; 13 | import javax.crypto.spec.SecretKeySpec; 14 | import java.io.UnsupportedEncodingException; 15 | import java.net.URLEncoder; 16 | import java.nio.charset.StandardCharsets; 17 | import java.security.InvalidKeyException; 18 | import java.security.NoSuchAlgorithmException; 19 | import java.util.Base64; 20 | 21 | /** 22 | * @author 汪小哥 23 | * @date 17-04-2021 24 | */ 25 | @Slf4j 26 | public class DingTalkRobotSender { 27 | 28 | /** 29 | * 钉钉机器人配置 webhook 30 | */ 31 | private String webhook; 32 | /** 33 | * 钉钉机器人加签关键字 34 | */ 35 | private String signSecret; 36 | 37 | /** 38 | * 发送速率 [每分钟最多20次] 1/3.5~= 0.2857 39 | */ 40 | private Double rateLimiterPermitsPerSecond = 0.2857; 41 | 42 | /** 43 | * 每个机器人每分钟最多发送20条 44 | */ 45 | private RateLimiter rateLimiter = null; 46 | 47 | public DingTalkRobotSender(String webhook, String signSecret, Double rateLimiterPermitsPerSecond) { 48 | this.webhook = webhook; 49 | this.signSecret = signSecret; 50 | if (rateLimiterPermitsPerSecond == null) { 51 | rateLimiterPermitsPerSecond = 0.2857; 52 | } 53 | rateLimiter = RateLimiter.create(rateLimiterPermitsPerSecond); 54 | } 55 | 56 | /** 57 | * 发送钉钉消息 58 | * 59 | * @param sendRequest 60 | */ 61 | public void sendToRobot(OapiRobotSendRequest sendRequest) { 62 | try { 63 | //每个机器人每分钟最多发送20条、限流处理一下 64 | rateLimiter.acquire(); 65 | Long timestamp = System.currentTimeMillis(); 66 | String url = webhook; 67 | if (StringUtils.hasText(signSecret)) { 68 | String sign = getSign(timestamp); 69 | url = url + "×tamp=" + timestamp + "&sign=" + sign; 70 | } 71 | DingTalkClient client = new DefaultDingTalkClient(url); 72 | try { 73 | OapiRobotSendResponse response = client.execute(sendRequest); 74 | if (!response.isSuccess()) { 75 | System.out.println(String.format("send dingtalk errorCode=%s errorMsg=%s", response.getErrcode(), response.getErrmsg())); 76 | } 77 | } catch (ApiException e) { 78 | System.out.println(String.format("send dingtalk api error=%s", e.getMessage())); 79 | } 80 | } catch (Exception e) { 81 | /** 82 | * 这里不能写日志了 83 | * @see ch.qos.logback.core.UnsynchronizedAppenderBase#addError(String) 84 | */ 85 | System.out.println(String.format("send dingtalk error last=%s", e.getMessage())); 86 | } 87 | } 88 | 89 | /** 90 | * 签名 91 | * 92 | * @param timestamp 93 | * @return 94 | */ 95 | private String getSign(Long timestamp) { 96 | String secret = this.signSecret; 97 | try { 98 | String stringToSign = timestamp + "\n" + secret; 99 | Mac mac = Mac.getInstance("HmacSHA256"); 100 | mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); 101 | byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); 102 | return URLEncoder.encode(new String(Base64.getEncoder().encode(signData)), StandardCharsets.UTF_8.name()); 103 | } catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeyException e) { 104 | e.printStackTrace(); 105 | } 106 | return ""; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/logback/append/DingTalkRobotAppend.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.logback.append; 2 | 3 | import ch.qos.logback.classic.encoder.PatternLayoutEncoder; 4 | import ch.qos.logback.classic.spi.ILoggingEvent; 5 | import ch.qos.logback.core.Layout; 6 | import ch.qos.logback.core.UnsynchronizedAppenderBase; 7 | import ch.qos.logback.core.encoder.Encoder; 8 | import ch.qos.logback.core.encoder.LayoutWrappingEncoder; 9 | import com.dingtalk.api.request.OapiRobotSendRequest; 10 | import com.github.wangji92.dingtalkrobot.core.DingTalkRobotSender; 11 | 12 | import java.nio.charset.StandardCharsets; 13 | 14 | 15 | /** 16 | * 实现异步 日志队列 17 | * 18 | * @author 汪小哥 19 | * @date 17-04-2021 20 | */ 21 | public class DingTalkRobotAppend extends UnsynchronizedAppenderBase { 22 | /** 23 | * 钉钉机器人配置 webhook 24 | */ 25 | private String webhook; 26 | /** 27 | * 钉钉机器人加签关键字 28 | */ 29 | private String signSecret; 30 | /** 31 | * 通知标题 32 | */ 33 | private String robotTitle; 34 | 35 | /** 36 | * 发送速率 [每分钟最多20次] 1/3.5~= 0.2857 37 | */ 38 | private Double rateLimiterPermitsPerSecond = 0.2857; 39 | 40 | /** 41 | * 定义 layout 处理器 Encode 42 | * 43 | * @see PatternLayoutEncoder 44 | * @see LayoutWrappingEncoder 45 | * {@literal http://logback.qos.ch/manual/encoders.html} 46 | */ 47 | private Encoder encoder; 48 | /** 49 | * 发送钉钉机器人消息 50 | */ 51 | private DingTalkRobotSender dingTalkRobotSender; 52 | 53 | public DingTalkRobotAppend() { 54 | super(); 55 | super.setName("dRobot"); 56 | } 57 | 58 | @Override 59 | protected void append(ILoggingEvent eventObject) { 60 | if (encoder == null) { 61 | addWarn("encoder is null"); 62 | return; 63 | } 64 | byte[] encodeBytes = encoder.encode(eventObject); 65 | if (dingTalkRobotSender != null) { 66 | OapiRobotSendRequest oapiRobotSendRequest = new OapiRobotSendRequest(); 67 | oapiRobotSendRequest.setMsgtype("markdown"); 68 | 69 | OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown(); 70 | markdown.setText(new String(encodeBytes, StandardCharsets.UTF_8)); 71 | markdown.setTitle(robotTitle); 72 | 73 | oapiRobotSendRequest.setMarkdown(markdown); 74 | dingTalkRobotSender.sendToRobot(oapiRobotSendRequest); 75 | } 76 | } 77 | 78 | @Override 79 | public void start() { 80 | if (webhook != null && webhook.length() > 0) { 81 | dingTalkRobotSender = new DingTalkRobotSender(webhook, signSecret,rateLimiterPermitsPerSecond); 82 | super.start(); 83 | } 84 | } 85 | 86 | public String getWebhook() { 87 | return webhook; 88 | } 89 | 90 | public void setWebhook(String webhook) { 91 | this.webhook = webhook; 92 | } 93 | 94 | public String getSignSecret() { 95 | return signSecret; 96 | } 97 | 98 | public void setSignSecret(String signSecret) { 99 | this.signSecret = signSecret; 100 | } 101 | 102 | 103 | /** 104 | * 设置 layout 105 | * 106 | * @param layout 107 | */ 108 | public void setLayout(Layout layout) { 109 | LayoutWrappingEncoder customLayoutEncoder = new LayoutWrappingEncoder(); 110 | customLayoutEncoder.setLayout(layout); 111 | customLayoutEncoder.setContext(context); 112 | this.encoder = customLayoutEncoder; 113 | 114 | } 115 | 116 | public Double getRateLimiterPermitsPerSecond() { 117 | return rateLimiterPermitsPerSecond; 118 | } 119 | 120 | public void setRateLimiterPermitsPerSecond(Double rateLimiterPermitsPerSecond) { 121 | this.rateLimiterPermitsPerSecond = rateLimiterPermitsPerSecond; 122 | } 123 | 124 | public Encoder getEncoder() { 125 | return encoder; 126 | } 127 | 128 | public void setEncoder(Encoder encoder) { 129 | this.encoder = encoder; 130 | } 131 | 132 | public String getRobotTitle() { 133 | return robotTitle; 134 | } 135 | 136 | public void setRobotTitle(String robotTitle) { 137 | this.robotTitle = robotTitle; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/logback/layout/DingTalkRobotLayout.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.logback.layout; 2 | 3 | import ch.qos.logback.classic.pattern.ClassOfCallerConverter; 4 | import ch.qos.logback.classic.pattern.LineOfCallerConverter; 5 | import ch.qos.logback.classic.pattern.MethodOfCallerConverter; 6 | import ch.qos.logback.classic.pattern.ThrowableProxyConverter; 7 | import ch.qos.logback.classic.spi.ILoggingEvent; 8 | import ch.qos.logback.classic.spi.IThrowableProxy; 9 | import ch.qos.logback.core.CoreConstants; 10 | import ch.qos.logback.core.LayoutBase; 11 | import com.github.wangji92.dingtalkrobot.logback.pattern.CenterBracketsTemplateConverter; 12 | import com.github.wangji92.dingtalkrobot.utils.IpUtils; 13 | import com.google.common.collect.Lists; 14 | import org.springframework.util.StringUtils; 15 | 16 | import java.text.SimpleDateFormat; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | /** 21 | * 解析处理日志 22 | * 23 | * @author 汪小哥 24 | * @date 17-04-2021 25 | */ 26 | public class DingTalkRobotLayout extends LayoutBase { 27 | /** 28 | * 环境 29 | */ 30 | private String env; 31 | /** 32 | * 应用名称 33 | */ 34 | private String app; 35 | /** 36 | * ip 地址 37 | */ 38 | private String ip = ""; 39 | 40 | /** 41 | * 钉钉通知 快捷链接 42 | */ 43 | private String clickDescription; 44 | /** 45 | * 快捷链接 后面追加ip 46 | */ 47 | private String clickUrl; 48 | 49 | /** 50 | * 需要打印的mdc的信息 51 | */ 52 | private List mdcList = Lists.newArrayList(); 53 | 54 | @Override 55 | public void start() { 56 | lineOfCallerConverter.start(); 57 | methodOfCallerConverter.start(); 58 | classOfCallerConverter.start(); 59 | methodOfCallerConverter.start(); 60 | throwableProxyConverter.setOptionList(Lists.newArrayList("5")); 61 | throwableProxyConverter.start(); 62 | ip = IpUtils.getIpAddress(); 63 | 64 | //处理动态的属性 https://kaifa.baidu.com/searchPage?wd=[localIp] 链接中的动态变量 65 | centerBracketsTemplateConverter.setOptionList(Lists.newArrayList(clickUrl)); 66 | centerBracketsTemplateConverter.setContext(getContext()); 67 | centerBracketsTemplateConverter.start(); 68 | super.start(); 69 | } 70 | 71 | private static final ThreadLocal DATE_FORMAT_THREAD_LOCAL = new ThreadLocal() { 72 | @Override 73 | protected SimpleDateFormat initialValue() { 74 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 75 | } 76 | }; 77 | 78 | private LineOfCallerConverter lineOfCallerConverter = new LineOfCallerConverter(); 79 | private MethodOfCallerConverter methodOfCallerConverter = new MethodOfCallerConverter(); 80 | private ClassOfCallerConverter classOfCallerConverter = new ClassOfCallerConverter(); 81 | private ThrowableProxyConverter throwableProxyConverter = new ThrowableProxyConverter(); 82 | private CenterBracketsTemplateConverter centerBracketsTemplateConverter = new CenterBracketsTemplateConverter(); 83 | 84 | @Override 85 | public String doLayout(ILoggingEvent event) { 86 | if (!isStarted()) { 87 | return CoreConstants.EMPTY_STRING; 88 | } 89 | StringBuilder sb = new StringBuilder(); 90 | if (StringUtils.hasText(this.getPresentationHeader())) { 91 | sb.append("## ").append(this.getPresentationHeader()).append("\n"); 92 | } 93 | this.markdownTextAppend(sb, "env", env); 94 | this.markdownTextAppend(sb, "app", app); 95 | this.markdownTextAppend(sb, "ip", ip); 96 | this.markdownTextAppend(sb, "thread", event.getThreadName()); 97 | this.markdownTextAppend(sb, "level", event.getLevel().levelStr); 98 | // this.markdownTextAppend(sb, "logger", event.getLoggerName()); 99 | 100 | // String classConvert = classOfCallerConverter.convert(event); 101 | // this.markdownTextAppend(sb, "class", classConvert); 102 | 103 | String method = methodOfCallerConverter.convert(event); 104 | this.markdownTextAppend(sb, "method", method); 105 | 106 | String line = lineOfCallerConverter.convert(event); 107 | this.markdownTextAppend(sb, "line", line); 108 | 109 | this.mdcAppend(sb, event); 110 | 111 | this.markdownTextAppend(sb, "message", event.getFormattedMessage()); 112 | 113 | IThrowableProxy tp = event.getThrowableProxy(); 114 | if (tp != null) { 115 | String stackTrace = throwableProxyConverter.convert(event); 116 | this.markdownTextAppend(sb, "stackTrace", stackTrace); 117 | } 118 | 119 | //增加快捷链接 120 | if (StringUtils.hasText(clickDescription) && StringUtils.hasText(clickUrl)) { 121 | String clickUrlDetail = centerBracketsTemplateConverter.convert(event); 122 | this.markdownTextAppendUrl(sb, clickDescription, clickUrlDetail, clickUrlDetail); 123 | } 124 | return sb.toString(); 125 | } 126 | 127 | /** 128 | * md 格式 129 | * 130 | * @param sb 131 | * @param key 132 | * @param value 133 | */ 134 | private void markdownTextAppend(StringBuilder sb, String key, String value) { 135 | if (StringUtils.hasText(value)) { 136 | sb.append("- ").append(key).append(": ").append(value).append("\n"); 137 | } 138 | } 139 | 140 | /** 141 | * 增加链接 142 | * 143 | * @param sb 144 | * @param key 145 | * @param url 146 | * @param value 147 | */ 148 | private void markdownTextAppendUrl(StringBuilder sb, String key, String url, String value) { 149 | String link = String.format("[%s](%s)", value, url); 150 | sb.append("- ").append(key).append(": ").append(link).append("\n"); 151 | } 152 | 153 | /** 154 | * mdc 处理 155 | * 156 | * @param sb 157 | * @param event 158 | */ 159 | private void mdcAppend(StringBuilder sb, ILoggingEvent event) { 160 | Map mdcPropertyMap = event.getMDCPropertyMap(); 161 | for (Map.Entry entry : mdcPropertyMap.entrySet()) { 162 | if (StringUtils.hasText(entry.getKey()) && StringUtils.hasText(entry.getValue()) && mdcList.contains(entry.getKey())) { 163 | this.markdownTextAppend(sb, entry.getKey(), entry.getValue()); 164 | } 165 | } 166 | } 167 | 168 | public String getEnv() { 169 | return env; 170 | } 171 | 172 | public void setEnv(String env) { 173 | this.env = env; 174 | } 175 | 176 | public String getApp() { 177 | return app; 178 | } 179 | 180 | public void setApp(String app) { 181 | this.app = app; 182 | } 183 | 184 | public String getClickDescription() { 185 | return clickDescription; 186 | } 187 | 188 | public void setClickDescription(String clickDescription) { 189 | this.clickDescription = clickDescription; 190 | } 191 | 192 | public String getClickUrl() { 193 | return clickUrl; 194 | } 195 | 196 | public void setClickUrl(String clickUrl) { 197 | this.clickUrl = clickUrl; 198 | } 199 | 200 | public List getMdcList() { 201 | return mdcList; 202 | } 203 | 204 | public void setMdcList(List mdcList) { 205 | if (mdcList == null) { 206 | return; 207 | } 208 | this.mdcList = mdcList; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/logback/listener/LoggerStartupListener.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.logback.listener; 2 | 3 | import ch.qos.logback.classic.Level; 4 | import ch.qos.logback.classic.Logger; 5 | import ch.qos.logback.classic.LoggerContext; 6 | import ch.qos.logback.classic.spi.LoggerContextListener; 7 | import ch.qos.logback.core.spi.ContextAwareBase; 8 | import ch.qos.logback.core.spi.LifeCycle; 9 | import com.github.wangji92.dingtalkrobot.logback.property.LocalIpDefiner; 10 | 11 | /** 12 | * @author 汪小哥 13 | * @date 18-04-2021 14 | */ 15 | public class LoggerStartupListener extends ContextAwareBase implements LoggerContextListener, LifeCycle { 16 | 17 | private boolean started = false; 18 | 19 | private LocalIpDefiner localIpDefiner = new LocalIpDefiner(); 20 | 21 | @Override 22 | public boolean isResetResistant() { 23 | return false; 24 | } 25 | 26 | @Override 27 | public void onStart(LoggerContext context) { 28 | 29 | } 30 | 31 | @Override 32 | public void onReset(LoggerContext context) { 33 | 34 | } 35 | 36 | @Override 37 | public void onStop(LoggerContext context) { 38 | 39 | } 40 | 41 | @Override 42 | public void onLevelChange(Logger logger, Level level) { 43 | 44 | } 45 | 46 | @Override 47 | public void start() { 48 | if (started) { 49 | return; 50 | } 51 | context.putProperty("localIp", localIpDefiner.getPropertyValue()); 52 | started = true; 53 | } 54 | 55 | @Override 56 | public void stop() { 57 | 58 | } 59 | 60 | @Override 61 | public boolean isStarted() { 62 | return started; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/logback/pattern/CenterBracketsTemplateConverter.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.logback.pattern; 2 | 3 | import ch.qos.logback.classic.pattern.ClassicConverter; 4 | import ch.qos.logback.classic.spi.ILoggingEvent; 5 | import ch.qos.logback.core.Context; 6 | import org.springframework.util.StringUtils; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | /** 14 | * 中括号中变量处理 比如 https://kaifa.baidu.com/searchPage?w=[localIp] 15 | * https://blog.csdn.net/WuLex/article/details/82116701 16 | * https://xie.infoq.cn/article/73d2aa78bac23f1bd2731ed23 17 | * 18 | * @author 汪小哥 19 | * @date 19-04-2021 20 | */ 21 | public class CenterBracketsTemplateConverter extends ClassicConverter { 22 | 23 | private static final String REGEX = "(?<=\\[)([a-zA-Z0-9]*)(?=\\])"; 24 | 25 | /** 26 | * 缓存值 第一次处理即可 27 | */ 28 | private String convertContentCache = ""; 29 | 30 | @Override 31 | public String convert(ILoggingEvent event) { 32 | if (StringUtils.hasText(convertContentCache)) { 33 | return convertContentCache; 34 | } 35 | 36 | if (getFirstOption() == null) { 37 | return ""; 38 | } 39 | String firstOption = getFirstOption(); 40 | Context context = getContext(); 41 | Pattern compile = Pattern.compile(REGEX); 42 | Matcher matcher = compile.matcher(getFirstOption()); 43 | Map map = new HashMap<>(3); 44 | while (matcher.find()) { 45 | for (int index = 1; index <= matcher.groupCount(); index++) { 46 | String propertyValue = context.getProperty(matcher.group(index)); 47 | if (StringUtils.hasText(propertyValue)) { 48 | map.put(matcher.group(index), propertyValue); 49 | } 50 | } 51 | } 52 | for (Map.Entry keyValue : map.entrySet()) { 53 | firstOption = firstOption.replace("[" + keyValue.getKey() + "]", keyValue.getValue()); 54 | } 55 | convertContentCache = firstOption; 56 | return firstOption; 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/logback/property/LocalIpDefiner.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.logback.property; 2 | 3 | import ch.qos.logback.core.PropertyDefinerBase; 4 | import com.github.wangji92.dingtalkrobot.utils.IpUtils; 5 | 6 | /** 7 | * how to define value {@literal https://blog.csdn.net/acohi68664/article/details/102178465} 8 | * 然后在logback.xml中,添加 配置,指定属性名(本例中为localIP)及获取属性值的实现类,这样就可以在配置中通过 ${localIp}来引用该属性值了。 9 | * 10 | * 11 | * @author 汪小哥 12 | * @date 18-04-2021 13 | */ 14 | public class LocalIpDefiner extends PropertyDefinerBase { 15 | @Override 16 | public String getPropertyValue() { 17 | return IpUtils.getIpAddress(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/wangji92/dingtalkrobot/utils/IpUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.wangji92.dingtalkrobot.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.net.Inet4Address; 6 | import java.net.InetAddress; 7 | import java.net.NetworkInterface; 8 | import java.util.Enumeration; 9 | 10 | /** 11 | * 获取本机ip 12 | * 13 | * @author jet 14 | * @date 20-11-2019 15 | */ 16 | @Slf4j 17 | public class IpUtils { 18 | 19 | /** 20 | * 获取本机Ip 21 | * 22 | * @return 23 | */ 24 | public static String getIpAddress() { 25 | try { 26 | Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces(); 27 | InetAddress ip = null; 28 | while (allNetInterfaces.hasMoreElements()) { 29 | NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement(); 30 | if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) { 31 | // 32 | } else { 33 | Enumeration addresses = netInterface.getInetAddresses(); 34 | while (addresses.hasMoreElements()) { 35 | ip = addresses.nextElement(); 36 | if (ip instanceof Inet4Address) { 37 | return ip.getHostAddress(); 38 | } 39 | } 40 | } 41 | } 42 | } catch (Exception e) { 43 | log.warn("getIpAddress error", e); 44 | } 45 | return ""; 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.github.wangji92.dingtalkrobot.DingTalkRobotAppendAutoConfiguration -------------------------------------------------------------------------------- /src/main/resources/com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-base.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 25 | 26 | 28 | 29 | 30 | 32 | 34 | 37 | 38 | 39 | 41 | 42 | 43 | 45 | 46 | 47 | 49 | 50 | 51 | 53 | 54 | 55 | 57 | 58 | 59 | 61 | 62 | 63 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/resources/com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-custom-layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 15 | ${dingTalkRobotWebhook} 16 | ${dingTalkRobotSignSecret} 17 | ${dingTalkRobotTitle} 18 | ${dingTalkRateLimiterPermitsPerSecond:-0.2875} 19 | 20 | ${env} 21 | ${app} 22 | ${dingTalkQuickLinkClickDescription} 23 | ${dingTalkQuickLinkClickUrl} 24 | 25 | 26 | 27 | 28 | ${asyncAppenderIncludeCallerData:-true} 29 | ${asyncAppenderQueueSize:-256} 30 | ${asyncAppenderNeverBlock:-true} 31 | 32 | 33 | ${dingTalkLogLevel:-ERROR} 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ${dingTalkLogConfigKewWordExpression} 43 | 44 | 45 | ACCEPT 46 | 47 | DENY 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/resources/com/github/wangji92/dingtalkrobot/logback-dingtalk-robot-pattern-layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 15 | ${dingTalkRobotWebhook} 16 | ${dingTalkRobotSignSecret} 17 | ${dingTalkRobotTitle} 18 | 19 | 20 | ${DINGTALK_ROBOT_LOG_PATTERN} 21 | UTF-8 22 | 23 | 24 | 25 | 26 | ${asyncAppenderIncludeCallerData:-true} 27 | ${asyncAppenderQueueSize:-256} 28 | ${asyncAppenderNeverBlock:-true} 29 | 30 | 31 | ${dingTalkLogLevel:-ERROR} 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ${dingTalkLogConfigKewWordExpression} 41 | 42 | 43 | ACCEPT 44 | 45 | DENY 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/main/resources/example/logback-dingtalk-robot-example.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ${CONSOLE_LOG_PATTERN} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/test/java/com/github/wangji92/dingtalkrobot/DingtalkRobotLogbackAlarmSpringBootStartApplicationTests.java: -------------------------------------------------------------------------------- 1 | //package com.github.wangji92.logback; 2 | // 3 | //import org.junit.jupiter.api.Test; 4 | //import org.springframework.boot.test.context.SpringBootTest; 5 | // 6 | //@SpringBootTest 7 | //class DingtalkRobotLogbackappendSpringBootStartApplicationTests { 8 | // 9 | // @Test 10 | // void contextLoads() { 11 | // } 12 | // 13 | //} 14 | --------------------------------------------------------------------------------