├── minbox-logging-admin-ui ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── api-boot-logging-admin-ui │ │ │ └── .gitignore │ │ ├── frontend │ │ ├── shell │ │ │ ├── i18n.zh.json │ │ │ └── index.vue │ │ ├── views │ │ │ ├── logs │ │ │ │ └── i18n.zh.json │ │ │ ├── about │ │ │ │ └── i18n.zh.json │ │ │ ├── wallboard │ │ │ │ ├── i18n.zh.json │ │ │ │ └── hex-mesh.spec.js │ │ │ └── index.js │ │ ├── assets │ │ │ ├── img │ │ │ │ ├── favicon.ico │ │ │ │ ├── apiboot-white.png │ │ │ │ └── apiboot-colorful.png │ │ │ └── css │ │ │ │ └── _utilities.scss │ │ ├── components │ │ │ ├── __snapshots__ │ │ │ │ ├── sba-time-ago.spec.js.snap │ │ │ │ └── sba-status.spec.js.snap │ │ │ ├── index.js │ │ │ ├── sba-tags.vue │ │ │ ├── sba-time-ago.js │ │ │ ├── sba-formatted-obj.vue │ │ │ ├── sba-time-ago.spec.js │ │ │ ├── sba-icon-button.vue │ │ │ ├── sba-confirm-button.vue │ │ │ ├── sba-status.spec.js │ │ │ ├── sba-status.vue │ │ │ └── sba-panel.vue │ │ ├── login.i18n.zh.json │ │ ├── utils │ │ │ ├── uri.js │ │ │ ├── eventsource-polyfill.js │ │ │ ├── d3.js │ │ │ ├── uri.spec.js │ │ │ ├── collections.js │ │ │ ├── shortenClassname.js │ │ │ ├── autolink.js │ │ │ ├── axios.js │ │ │ ├── shortenClassname.spec.js │ │ │ ├── objToString.spec.js │ │ │ ├── objToString.js │ │ │ ├── axios.spec.js │ │ │ ├── autolink.spec.js │ │ │ ├── logtail.js │ │ │ ├── rxjs.js │ │ │ ├── rxjs.spec.js │ │ │ └── collections.spec.js │ │ ├── i18n │ │ │ ├── index.js │ │ │ └── i18n.zh.json │ │ ├── sba-settings.js │ │ ├── login.js │ │ ├── index.html │ │ ├── directives │ │ │ ├── sticks-below.js │ │ │ ├── on-resize.js │ │ │ └── popper.js │ │ ├── mixins │ │ │ └── subscribing.js │ │ ├── sba-config.js │ │ ├── store.spec.js │ │ ├── viewRegistry.js │ │ ├── services │ │ │ ├── application.spec.js │ │ │ ├── notification-filter.js │ │ │ └── application.js │ │ └── store.js │ │ └── java │ │ └── org │ │ └── minbox │ │ └── framework │ │ └── logging │ │ └── admin │ │ └── ui │ │ ├── HomepageForwardingFilter.java │ │ └── HomepageForwardingMatcher.java ├── .gitignore └── babel.config.js ├── minbox-logging-samples ├── logging-client-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.yml │ │ │ └── java │ │ │ └── org │ │ │ └── minbox │ │ │ └── framework │ │ │ └── logging │ │ │ └── client │ │ │ └── sample │ │ │ ├── CustomerTraceIdGenerator.java │ │ │ ├── CustomerSpanIdGenerator.java │ │ │ ├── LoggingClientSampleApplication.java │ │ │ ├── CustomerLoggingNotice.java │ │ │ ├── TestController.java │ │ │ └── LoggingClientConfiguration.java │ └── pom.xml ├── logging-admin-sample │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── application.yml │ │ │ └── java │ │ │ └── org │ │ │ └── minbox │ │ │ └── framework │ │ │ └── logging │ │ │ └── admin │ │ │ └── sample │ │ │ ├── LoggingAdminSampleApplication.java │ │ │ ├── LoggingAdminConfiguration.java │ │ │ └── CustomerReportEventListener.java │ └── pom.xml └── pom.xml ├── minbox-logging-core ├── src │ └── main │ │ └── java │ │ └── org │ │ └── minbox │ │ └── framework │ │ └── logging │ │ └── core │ │ ├── GlobalLogLevel.java │ │ ├── response │ │ ├── ServiceResponse.java │ │ ├── LoggingResponse.java │ │ └── ReportResponse.java │ │ ├── ReportAway.java │ │ ├── annotation │ │ └── Endpoint.java │ │ ├── GlobalLog.java │ │ ├── mapping │ │ └── LoggingRequestMappingHandlerMapping.java │ │ └── LoggingClientNotice.java └── pom.xml ├── .gitignore ├── codecov.yml ├── minbox-logging-client ├── src │ └── main │ │ └── java │ │ └── org │ │ └── minbox │ │ └── framework │ │ └── logging │ │ └── client │ │ ├── admin │ │ ├── discovery │ │ │ ├── lb │ │ │ │ ├── LoadBalanceStrategy.java │ │ │ │ ├── LoadBalanceNode.java │ │ │ │ └── support │ │ │ │ │ ├── DefaultLoadBalanceStrategy.java │ │ │ │ │ ├── RandomWeightedStrategy.java │ │ │ │ │ └── SmoothWeightedRoundRobinStrategy.java │ │ │ ├── support │ │ │ │ └── LoggingAbstractAdminDiscovery.java │ │ │ └── LoggingAdminDiscovery.java │ │ └── report │ │ │ ├── retry │ │ │ ├── LoggingReportRetry.java │ │ │ └── LoggingReportRetrySupport.java │ │ │ ├── LoggingAdminReport.java │ │ │ └── LoggingReportScheduled.java │ │ ├── interceptor │ │ ├── LoggingInterceptor.java │ │ ├── LoggingAbstractInterceptor.java │ │ └── webflux │ │ │ └── LoggingWebFluxInterceptor.java │ │ ├── MinBoxLoggingException.java │ │ ├── span │ │ ├── support │ │ │ ├── MinBoxSequenceLogSpanIdGenerator.java │ │ │ └── DefaultLogSpanIdGenerator.java │ │ └── LogSpanIdGenerator.java │ │ ├── tracer │ │ ├── support │ │ │ ├── MinBoxSequenceLogTraceIdGenerator.java │ │ │ └── DefaultLogTraceIdGenerator.java │ │ └── LogTraceIdGenerator.java │ │ ├── LoggingConstant.java │ │ ├── notice │ │ ├── LoggingNotice.java │ │ ├── LoggingNoticeEvent.java │ │ └── support │ │ │ ├── LoggingLocalNotice.java │ │ │ └── LoggingAdminNotice.java │ │ ├── global │ │ ├── GlobalLoggingThreadLocal.java │ │ ├── GlobalLogging.java │ │ └── support │ │ │ └── GlobalLoggingMemoryStorage.java │ │ ├── cache │ │ └── LoggingCache.java │ │ ├── LogThreadLocal.java │ │ ├── http │ │ ├── openfeign │ │ │ └── LoggingOpenFeignInterceptor.java │ │ └── rest │ │ │ └── LoggingRestTemplateInterceptor.java │ │ └── filter │ │ └── LoggingBodyFilter.java └── pom.xml ├── minbox-logging-spring-context ├── src │ └── main │ │ └── java │ │ └── org │ │ └── minbox │ │ └── framework │ │ └── logging │ │ └── spring │ │ └── context │ │ └── annotation │ │ ├── admin │ │ ├── EnableLoggingAdmin.java │ │ └── LoggingAdminBeanDefinitionRegistrar.java │ │ └── client │ │ ├── EnableLoggingClient.java │ │ └── LoggingClientBeanDefinitionRegistrar.java └── pom.xml ├── .travis.yml ├── CHANGELOG.md ├── minbox-logging-admin ├── src │ └── main │ │ └── java │ │ └── org │ │ └── minbox │ │ └── framework │ │ └── logging │ │ └── admin │ │ ├── storage │ │ ├── mongo │ │ │ ├── GlobalLogMongoEntity.java │ │ │ ├── RequestLogMongoEntity.java │ │ │ ├── MongoCollectionFields.java │ │ │ ├── ServiceEntity.java │ │ │ └── MongoCollectionNames.java │ │ └── LoggingDefaultStorage.java │ │ └── event │ │ └── ReportLogEvent.java └── pom.xml ├── .github └── workflows │ └── deploy.yml └── minbox-logging-dependencies └── pom.xml /minbox-logging-admin-ui/src/main/resources/META-INF/api-boot-logging-admin-ui/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/shell/i18n.zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "navbar": { 3 | "logout": "退出登录" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/views/logs/i18n.zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "logs": { 3 | "title": "链路日志列表", 4 | "label": "链路日志" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/views/about/i18n.zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "about": { 3 | "title": "关于ApiBoot Logging Admin", 4 | "label": "关于" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/assets/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minbox-projects/minbox-logging/HEAD/minbox-logging-admin-ui/src/main/frontend/assets/img/favicon.ico -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/assets/img/apiboot-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minbox-projects/minbox-logging/HEAD/minbox-logging-admin-ui/src/main/frontend/assets/img/apiboot-white.png -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/assets/img/apiboot-colorful.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minbox-projects/minbox-logging/HEAD/minbox-logging-admin-ui/src/main/frontend/assets/img/apiboot-colorful.png -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/views/wallboard/i18n.zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "wallboard": { 3 | "instances_count": "no instances | {count} instance | {count} instances", 4 | "label": "首页" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | main: 3 | allow-circular-references: true 4 | application: 5 | name: logging-client-sample 6 | server: 7 | port: 8080 8 | 9 | logging: 10 | level: 11 | org.minbox.framework.logging.client: debug -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/__snapshots__/sba-time-ago.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`time-ago given a short time passed time should match the snapshot 1`] = `14m`; 4 | 5 | exports[`time-ago given a long time passed time should match the snapshot 1`] = `Jul 7`; 6 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/GlobalLogLevel.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.core; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * Global Log Level 7 | * 8 | * @author 恒宇少年 9 | */ 10 | @Getter 11 | public enum GlobalLogLevel { 12 | debug, 13 | info, 14 | error 15 | } 16 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/login.i18n.zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": { 3 | "button_login": "登录", 4 | "invalid_username_or_password": "用户名或密码错误", 5 | "logout_successful": "退出成功", 6 | "remember_me": "记住我", 7 | "placeholder": { 8 | "username": "用户名", 9 | "password": "密码" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | # local env files 5 | .env.local 6 | .env.*.local 7 | 8 | # Log files 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.sw? 21 | 22 | /target/ -------------------------------------------------------------------------------- /minbox-logging-samples/logging-admin-sample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9091 3 | spring: 4 | application: 5 | name: logging-admin-sample 6 | datasource: 7 | driver-class-name: com.mysql.cj.jdbc.Driver 8 | type: com.zaxxer.hikari.HikariDataSource 9 | username: root 10 | password: 123456 11 | url: jdbc:mysql://localhost:3308/test 12 | 13 | logging: 14 | level: 15 | org.minbox.framework.logging.admin: debug -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.mvn/wrapper/maven-wrapper.jar 2 | 3 | ### target ### 4 | target 5 | 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | /build/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | 32 | .flattened-pom.xml -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: yes 3 | coverage: 4 | status: 5 | patch: no 6 | project: 7 | default: 8 | threshold: 1% 9 | if_not_found: success 10 | changes: no 11 | precision: 2 12 | range: "50...100" 13 | ignore: 14 | - "test/.*" 15 | - ".github/.*" 16 | - ".mvn/.*" 17 | - ".style/.*" 18 | - "*.md" 19 | comment: 20 | layout: "reach,diff,flags,tree" 21 | behavior: default 22 | require_changes: no 23 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/discovery/lb/LoadBalanceStrategy.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.admin.discovery.lb; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | 5 | /** 6 | * Load balance strategy 7 | * 8 | * @author 恒宇少年 9 | */ 10 | public interface LoadBalanceStrategy { 11 | /** 12 | * lookup Load-balanced addresses 13 | * 14 | * @param adminAddress logging admin address array 15 | * @return Load-balanced addresses 16 | * @throws MinBoxLoggingException MinBox Logging Exception 17 | */ 18 | String lookup(String[] adminAddress) throws MinBoxLoggingException; 19 | } 20 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/src/main/java/org/minbox/framework/logging/client/sample/CustomerTraceIdGenerator.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.sample; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | import org.minbox.framework.logging.client.tracer.LogTraceIdGenerator; 5 | 6 | import java.util.UUID; 7 | 8 | /** 9 | * 自定义链路编号(TraceID){@link LogTraceIdGenerator} 10 | * 11 | * @author 恒宇少年 12 | */ 13 | public class CustomerTraceIdGenerator implements LogTraceIdGenerator { 14 | @Override 15 | public String createTraceId() throws MinBoxLoggingException { 16 | return UUID.randomUUID().toString().replace("-", ""); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/src/main/java/org/minbox/framework/logging/client/sample/CustomerSpanIdGenerator.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.sample; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | import org.minbox.framework.logging.client.span.LogSpanIdGenerator; 5 | 6 | /** 7 | * 自定义单元编号(SpanID){@link LogSpanIdGenerator} 8 | * 9 | * @author 恒宇少年 10 | */ 11 | public class CustomerSpanIdGenerator implements LogSpanIdGenerator { 12 | @Override 13 | public String createSpanId() throws MinBoxLoggingException { 14 | String currentTime = String.valueOf(System.currentTimeMillis()); 15 | return String.format("%s-%s", "span", currentTime); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/interceptor/LoggingInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.interceptor; 2 | 3 | import org.minbox.framework.logging.client.span.LogSpanIdGenerator; 4 | import org.minbox.framework.logging.client.tracer.LogTraceIdGenerator; 5 | 6 | /** 7 | * MinBox logging interceptor 8 | * 9 | * @author 恒宇少年 10 | */ 11 | public interface LoggingInterceptor { 12 | /** 13 | * create new traceId 14 | * {@link LogTraceIdGenerator} 15 | * 16 | * @return traceId 17 | */ 18 | String createTraceId(); 19 | 20 | /** 21 | * create new spanId 22 | * {@link LogSpanIdGenerator} 23 | * 24 | * @return spanId 25 | */ 26 | String createSpanId(); 27 | } 28 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/babel.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | module.exports = { 18 | presets: [ 19 | '@vue/app' 20 | ] 21 | }; 22 | -------------------------------------------------------------------------------- /minbox-logging-spring-context/src/main/java/org/minbox/framework/logging/spring/context/annotation/admin/EnableLoggingAdmin.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.spring.context.annotation.admin; 2 | 3 | import org.springframework.context.annotation.Import; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Enable Logging Admin Service 12 | * register logging admin {@link LoggingAdminBeanDefinitionRegistrar} beans 13 | * use {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} register beans 14 | * 15 | * @author 恒宇少年 16 | */ 17 | @Retention(RetentionPolicy.RUNTIME) 18 | @Target(ElementType.TYPE) 19 | @Import(LoggingAdminBeanDefinitionRegistrar.class) 20 | public @interface EnableLoggingAdmin { 21 | } 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false # faster builds 3 | jdk: 4 | - openjdk8 5 | node_js: "10" 6 | cache: 7 | directories: 8 | - $HOME/.m2 9 | - $HOME/.npm 10 | - node_modules 11 | env: 12 | global: 13 | - TRAVIS_WORKER_HARD_TIMEOUT="80m" 14 | - TRAVIS_WORKER_LOG_TIMEOUT="30m" 15 | # Setting Maximum Log Length to 100MB 16 | - TRAVIS_WORKER_MAX_LOG_LENGTH=100000000 17 | before_script: 18 | - npm install 19 | # See details https://github.com/codecov/example-java-maven 20 | script: 21 | - mvn cobertura:cobertura 22 | # Extend the waiting time for executing commands to 30 minutes 23 | install: mvn clean install -Dmaven.javadoc.skip=true -Dgpg.skip=true -DskipNpmBuild=true -Dmaven.test.skip=true 24 | # Report to codecov 25 | after_success: 26 | - bash <(curl -s https://codecov.io/bash) 27 | notifications: 28 | email: 29 | - jnyuqy@gmail.com 30 | -------------------------------------------------------------------------------- /minbox-logging-spring-context/src/main/java/org/minbox/framework/logging/spring/context/annotation/client/EnableLoggingClient.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.spring.context.annotation.client; 2 | 3 | import org.springframework.context.annotation.Import; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Enable Logging Client Service 12 | * register logging client {@link LoggingClientBeanDefinitionRegistrar} beans 13 | * use {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} register beans 14 | * 15 | * @author 恒宇少年 16 | */ 17 | @Retention(RetentionPolicy.RUNTIME) 18 | @Target(ElementType.TYPE) 19 | @Import(LoggingClientBeanDefinitionRegistrar.class) 20 | public @interface EnableLoggingClient { 21 | } 22 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/response/ServiceResponse.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.core.response; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.Accessors; 5 | 6 | import java.time.LocalDateTime; 7 | 8 | /** 9 | * logging service response 10 | * 11 | * @author 恒宇少年 12 | */ 13 | @Data 14 | @Accessors(chain = true) 15 | public class ServiceResponse { 16 | /** 17 | * service application name 18 | * service id 19 | */ 20 | private String id; 21 | /** 22 | * service ip address 23 | */ 24 | private String ip; 25 | /** 26 | * service port 27 | */ 28 | private Integer port; 29 | /** 30 | * last report time 31 | */ 32 | private LocalDateTime lastReportTime; 33 | /** 34 | * first report time 35 | */ 36 | private LocalDateTime createTime; 37 | } 38 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/MinBoxLoggingException.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client; 2 | 3 | import lombok.NoArgsConstructor; 4 | 5 | /** 6 | * Custom runtime log exception 7 | * 8 | * @author 恒宇少年 9 | */ 10 | @NoArgsConstructor 11 | public class MinBoxLoggingException extends RuntimeException { 12 | /** 13 | * Constructor initializes exception object 14 | * 15 | * @param message Exception message 16 | */ 17 | public MinBoxLoggingException(String message) { 18 | super(message); 19 | } 20 | 21 | /** 22 | * Constructor initializes exception object 23 | * 24 | * @param message Exception message 25 | * @param cause {@link Throwable} stack information 26 | */ 27 | public MinBoxLoggingException(String message, Throwable cause) { 28 | super(message, cause); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/uri.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | export default (strings, ...values) => { 18 | let result = strings[0]; 19 | for (let i = 0; i < values.length; ++i) { 20 | result += encodeURIComponent(values[i]) + strings[i + 1]; 21 | } 22 | return result; 23 | } 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.2.RELEASE 更新日志 2 | 3 | - 升级使用minbox-framework版本为1.0.2.RELEASE 4 | - 添加GlobalLogging全局业务日志的概念 5 | - 支持将GlobalLog日志保存到数据库 6 | - 修改LocalNotice本次日志通知的优先级 7 | - 修改AdminNotice上报日志到Admin的优先级 8 | - 添加支持定时上报到Admin功能支持 9 | - 添加支持debug、info、error等类型的GlobalLog上报 10 | - 添加GlobalLoggingMemoryStorage用于内存临时存储一次请求的GlobalLog列表 11 | - 修改日志上报到Admin时的Content-Type 12 | - 添加logging_global_logs表结构 13 | - 支持采集error等级的GlobalLog堆栈错误信息 14 | 15 | ## 1.0.1.RELEASE 更新日志 16 | 17 | - logging-client支持配置多个指定logging-admin地址 18 | - logging-client支持平滑权重负载均衡上报指定logging-admin 19 | - logging-client支持随机权重负载均衡上报指定logging-admin 20 | - logging-admin支持不配置basic auth用户名、密码信息 21 | - 修改LoggingFactoryBean初始化配置方式为afterPropertiesSet 22 | - logging-client排除强制上报到logging-admin 23 | - logging-admin支持自定义LoggingStorage存储日志 24 | - logging-admin排除强依赖DataSource 25 | - logging-admin删除LoggingAdminUiFactoryBean配置,合并到LoggingAdminFactoryBean内UiSetting 26 | - logging-client修改LoggingInterceptor为LoggingWebInterceptor -------------------------------------------------------------------------------- /minbox-logging-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging-dependencies 7 | org.minbox.framework 8 | ${revision} 9 | ../minbox-logging-dependencies 10 | 11 | 4.0.0 12 | minbox-logging-core 13 | jar 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | true 19 | 20 | 21 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/eventsource-polyfill.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | export default async () => { 18 | if (typeof window.EventSource === 'undefined') { 19 | return import(/* webpackChunkName: "event-source-polyfill" */ 'event-source-polyfill'); 20 | } 21 | return Promise.resolve(); 22 | }; 23 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-admin-sample/src/main/java/org/minbox/framework/logging/admin/sample/LoggingAdminSampleApplication.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.admin.sample; 2 | 3 | import org.minbox.framework.logging.spring.context.annotation.admin.EnableLoggingAdmin; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | 9 | /** 10 | * @author 恒宇少年 11 | */ 12 | @SpringBootApplication 13 | @EnableLoggingAdmin 14 | public class LoggingAdminSampleApplication { 15 | /** 16 | * logger instance 17 | */ 18 | static Logger logger = LoggerFactory.getLogger(LoggingAdminSampleApplication.class); 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(LoggingAdminSampleApplication.class, args); 22 | logger.info("{}服务启动成功.", "Logging Admin Sample"); 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/src/main/java/org/minbox/framework/logging/client/sample/LoggingClientSampleApplication.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.sample; 2 | 3 | import org.minbox.framework.logging.spring.context.annotation.client.EnableLoggingClient; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | 9 | /** 10 | * Logging Client 示例 11 | * 12 | * @author 恒宇少年 13 | */ 14 | @SpringBootApplication 15 | @EnableLoggingClient 16 | public class LoggingClientSampleApplication { 17 | /** 18 | * logger instance 19 | */ 20 | static Logger logger = LoggerFactory.getLogger(LoggingClientSampleApplication.class); 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(LoggingClientSampleApplication.class, args); 24 | logger.info("{}服务启动成功.", "Logging Client Sample"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/src/main/java/org/minbox/framework/logging/client/sample/CustomerLoggingNotice.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.sample; 2 | 3 | import org.minbox.framework.logging.client.notice.LoggingNotice; 4 | import org.minbox.framework.logging.core.MinBoxLog; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * 自定义日志通知 9 | * 当不上报日志到`Logging Admin`时,可使用{@link LoggingNotice}来进行本地处理日志 10 | * 上报日志与本地处理不冲突,可并存 11 | * 12 | * @author 恒宇少年 13 | */ 14 | @Component 15 | public class CustomerLoggingNotice implements LoggingNotice { 16 | /** 17 | * 通知方法 18 | * 19 | * @param minBoxLog ApiBoot Log 20 | */ 21 | @Override 22 | public void notice(MinBoxLog minBoxLog) { 23 | System.out.println(minBoxLog.getTraceId()); 24 | } 25 | 26 | /** 27 | * 通知执行优先级 28 | * {@link #getOrder()}方法返回值值越小优先级越高 29 | * 30 | * @return 31 | */ 32 | @Override 33 | public int getOrder() { 34 | return 1; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/report/retry/LoggingReportRetry.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.admin.report.retry; 2 | 3 | import org.minbox.framework.logging.core.MinBoxLog; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Request loggers retry interface definition 9 | * use to log recycling, log retry, file caching 10 | * 11 | * @author 恒宇少年 12 | */ 13 | public interface LoggingReportRetry { 14 | /** 15 | * Add {@link MinBoxLog} to retry log collection 16 | * 17 | * @param minBoxLog {@link MinBoxLog} 18 | */ 19 | void addToRetryCollection(MinBoxLog minBoxLog); 20 | 21 | /** 22 | * Add {@link MinBoxLog} list to retry log collection 23 | * 24 | * @param minBoxLogs {@link MinBoxLog} 25 | */ 26 | void addToRetryCollection(List minBoxLogs); 27 | 28 | /** 29 | * Get all {@link MinBoxLog} from retry collection 30 | * 31 | * @return {@link MinBoxLog} 32 | */ 33 | List getAllRetryLogs(); 34 | } 35 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/response/LoggingResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.core.response; 19 | 20 | import lombok.Data; 21 | import org.minbox.framework.logging.core.MinBoxLog; 22 | 23 | /** 24 | * Logging Response Api Entity 25 | * 26 | * @author 恒宇少年 27 | */ 28 | @Data 29 | public class LoggingResponse extends MinBoxLog { 30 | // ... 31 | } 32 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/span/support/MinBoxSequenceLogSpanIdGenerator.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.span.support; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | import org.minbox.framework.logging.client.span.LogSpanIdGenerator; 5 | import org.minbox.framework.sequence.Sequence; 6 | 7 | /** 8 | * Use "minbox-sequence" to generate spanId 9 | *

10 | * https://github.com/minbox-projects/minbox-sequence 11 | * 12 | * @author 恒宇少年 13 | */ 14 | public class MinBoxSequenceLogSpanIdGenerator implements LogSpanIdGenerator { 15 | private static final int DEFAULT_DATA_CENTER_ID = 1; 16 | private Sequence sequence; 17 | 18 | public MinBoxSequenceLogSpanIdGenerator() { 19 | this(DEFAULT_DATA_CENTER_ID); 20 | } 21 | 22 | public MinBoxSequenceLogSpanIdGenerator(int dataCenterId) { 23 | this.sequence = new Sequence(dataCenterId); 24 | } 25 | 26 | @Override 27 | public String createSpanId() throws MinBoxLoggingException { 28 | return String.valueOf(sequence.nextId()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/src/main/java/org/minbox/framework/logging/client/sample/TestController.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.sample; 2 | 3 | import org.minbox.framework.logging.client.global.GlobalLogging; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | /** 9 | * @author 恒宇少年 10 | */ 11 | @RestController 12 | public class TestController { 13 | 14 | @Autowired 15 | private GlobalLogging globalLogging; 16 | 17 | @GetMapping(value = "/test") 18 | public String test() { 19 | globalLogging.info("这是第一条日志内容"); 20 | callMethod2(); 21 | callMethod3(); 22 | return "测试日志接口"; 23 | } 24 | 25 | private void callMethod2() { 26 | globalLogging.debug("这是第二条"); 27 | } 28 | 29 | private void callMethod3() { 30 | try { 31 | int a = 3 / 0; 32 | } catch (Exception e) { 33 | globalLogging.error(e.getMessage(), e); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/i18n/index.js: -------------------------------------------------------------------------------- 1 | import merge from 'lodash/merge'; 2 | import Vue from 'vue'; 3 | import VueI18n from 'vue-i18n'; 4 | 5 | Vue.use(VueI18n); 6 | 7 | const context = require.context('../', true, /^\.\/*\/.*i18n\.?([^/]*)\.json$/); 8 | const messages = context.keys() 9 | .map(key => { 10 | const localeFromFile = /^\.\/*\/.*i18n\.?([^/]*)\.json$/.exec(key); 11 | const messages = context(key); 12 | if (localeFromFile[1]) { 13 | return { 14 | [localeFromFile[1]]: messages 15 | } 16 | } else { 17 | return messages; 18 | } 19 | }) 20 | .reduce((prev, cur) => merge(prev, cur), {}); 21 | 22 | export const AVAILABLE_LANGUAGES = Object.keys(messages); 23 | 24 | const browserLanguage = navigator.language.split('-')[0]; 25 | 26 | const i18n = new VueI18n({ 27 | fallbackLocale: 'zh', 28 | locale: AVAILABLE_LANGUAGES.includes(browserLanguage) ? browserLanguage : 'zh', 29 | silentFallbackWarn: process.env.NODE_ENV === 'production', 30 | silentTranslationWarn: process.env.NODE_ENV === 'production', 31 | messages 32 | }); 33 | 34 | export default i18n; 35 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/tracer/support/MinBoxSequenceLogTraceIdGenerator.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.tracer.support; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | import org.minbox.framework.logging.client.tracer.LogTraceIdGenerator; 5 | import org.minbox.framework.sequence.Sequence; 6 | 7 | /** 8 | * Use "minbox-sequence" to generate traceId 9 | *

10 | * https://github.com/minbox-projects/minbox-sequence 11 | * 12 | * @author 恒宇少年 13 | */ 14 | public class MinBoxSequenceLogTraceIdGenerator implements LogTraceIdGenerator { 15 | private static final int DEFAULT_DATA_CENTER_ID = 1; 16 | private Sequence sequence; 17 | 18 | public MinBoxSequenceLogTraceIdGenerator() { 19 | this(DEFAULT_DATA_CENTER_ID); 20 | } 21 | 22 | public MinBoxSequenceLogTraceIdGenerator(int dataCenterId) { 23 | this.sequence = new Sequence(dataCenterId); 24 | } 25 | 26 | @Override 27 | public String createTraceId() throws MinBoxLoggingException { 28 | return String.valueOf(sequence.nextId()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/d3.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 * as array from 'd3-array'; 18 | import * as axis from 'd3-axis'; 19 | import * as brush from 'd3-brush'; 20 | import * as scale from 'd3-scale'; 21 | import * as selection from 'd3-selection'; 22 | import * as shape from 'd3-shape'; 23 | import * as time from 'd3-time'; 24 | 25 | export default { 26 | ...array, 27 | ...axis, 28 | ...brush, 29 | ...scale, 30 | ...selection, 31 | ...shape, 32 | ...time 33 | } 34 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/sba-settings.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 | //This is a Thymleaf template whill will be rendered by the backend 18 | var SBA = { 19 | uiSettings: /*[[${uiSettings}]]*/ {}, 20 | user: /*[[${user}]]*/ null, 21 | extensions: [], 22 | csrf: { 23 | parameterName: /*[[${_csrf} ? ${_csrf.parameterName} : 'null']]*/ null, 24 | headerName: /*[[${_csrf} ? ${_csrf.headerName} : 'null']]*/ null 25 | }, 26 | use: function (ext) { 27 | this.extensions.push(ext); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/login.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 '@/assets/css/base.scss'; 18 | import i18n from './i18n' 19 | 20 | document.querySelectorAll('[data-i18n]') 21 | .forEach(t => { 22 | let [attribute, key] = t.getAttribute('data-i18n').split(':'); 23 | if (!key) { 24 | key = attribute; 25 | attribute = undefined; 26 | } 27 | 28 | if (attribute) { 29 | t.setAttribute(attribute, i18n.t(key)); 30 | } else { 31 | t.innerHTML = i18n.t(key); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/response/ReportResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.core.response; 19 | 20 | import lombok.Data; 21 | 22 | /** 23 | * Report Request Log To Admin After Response Entity 24 | * 25 | * @author 恒宇少年 26 | */ 27 | @Data 28 | public class ReportResponse { 29 | 30 | public static final String SUCCESS = "SUCCESS"; 31 | 32 | public static final String ERROR = "ERROR"; 33 | 34 | private String status; 35 | } 36 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/ReportAway.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.core; 19 | 20 | import lombok.Getter; 21 | 22 | /** 23 | * Report Request Log To Admin Away 24 | * 25 | * @author:恒宇少年 - 于起宇 26 | */ 27 | @Getter 28 | public enum ReportAway { 29 | /** 30 | * just report to admin 31 | */ 32 | just, 33 | /** 34 | * timing report to admin with "reportIntervalSecond" config properties 35 | */ 36 | timing 37 | } 38 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | 18 | const components = []; 19 | 20 | /* global require */ 21 | const context = require.context('.', false, /^(?:(?!.*\.spec\.(js|vue)$).)*\.(js|vue)$/); 22 | context.keys().forEach(function (key) { 23 | const name = /^(.\/)+(.*)\.(vue|js)$/.exec(key)[2]; 24 | components.push({name, component: context(key).default}) 25 | }); 26 | 27 | export default { 28 | install(Vue) { 29 | components.forEach(component => Vue.component(component.name, component.component)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /minbox-logging-admin/src/main/java/org/minbox/framework/logging/admin/storage/mongo/GlobalLogMongoEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022. [恒宇少年 - 于起宇] 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 | * http://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 | package org.minbox.framework.logging.admin.storage.mongo; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Data; 21 | import lombok.NoArgsConstructor; 22 | import org.minbox.framework.logging.core.GlobalLog; 23 | 24 | /** 25 | * The {@link GlobalLog} mongo entity 26 | * 27 | * @author 恒宇少年 28 | */ 29 | @Data 30 | @NoArgsConstructor(access = AccessLevel.PACKAGE) 31 | class GlobalLogMongoEntity extends GlobalLog { 32 | private String _id; 33 | } 34 | -------------------------------------------------------------------------------- /minbox-logging-admin/src/main/java/org/minbox/framework/logging/admin/storage/mongo/RequestLogMongoEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022. [恒宇少年 - 于起宇] 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 | * http://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 | package org.minbox.framework.logging.admin.storage.mongo; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Data; 21 | import lombok.NoArgsConstructor; 22 | import org.minbox.framework.logging.core.MinBoxLog; 23 | 24 | /** 25 | * The {@link MinBoxLog} mongo entity 26 | * 27 | * @author 恒宇少年 28 | */ 29 | @Data 30 | @NoArgsConstructor(access = AccessLevel.PACKAGE) 31 | class RequestLogMongoEntity extends MinBoxLog { 32 | private String _id; 33 | } 34 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/uri.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 uri from './uri'; 18 | 19 | describe('uri', () => { 20 | 21 | it('should escape uris properly', () => { 22 | expect(uri`http://app/${'foo/bar'}?q=${'???'}`).toBe('http://app/foo%2Fbar?q=%3F%3F%3F'); 23 | expect(uri`http://app/${'foo/bar'}?q=1`).toBe('http://app/foo%2Fbar?q=1'); 24 | expect(uri`http://app/${'foo/bar'}`).toBe('http://app/foo%2Fbar'); 25 | expect(uri`http://app/foo`).toBe('http://app/foo'); 26 | expect(uri``).toBe(''); 27 | }); 28 | 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/LoggingConstant.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client; 19 | 20 | /** 21 | * Log Constant 22 | * 23 | * @author 恒宇少年 24 | */ 25 | public interface LoggingConstant { 26 | /** 27 | * TraceId Header Name 28 | */ 29 | String HEADER_NAME_TRACE_ID = "MINBOX-LOGGING-X-TRACE-ID"; 30 | /** 31 | * Parent SpanId Header Name 32 | */ 33 | String HEADER_NAME_PARENT_SPAN_ID = "MINBOX-LOGGING-X-PARENT-SPAN-ID"; 34 | } 35 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/collections.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 | export const compareBy = mapper => (a, b) => { 18 | const valA = mapper(a); 19 | const valB = mapper(b); 20 | return valA > valB ? 1 : valA < valB ? -1 : 0; 21 | }; 22 | 23 | export const anyValueMatches = (obj, predicate) => { 24 | if (Array.isArray(obj)) { 25 | return obj.some(e => anyValueMatches(e, predicate)); 26 | } else if (obj !== null && typeof obj === 'object') { 27 | return anyValueMatches(Object.values(obj), predicate); 28 | } 29 | return predicate(obj); 30 | }; 31 | -------------------------------------------------------------------------------- /minbox-logging-admin/src/main/java/org/minbox/framework/logging/admin/storage/mongo/MongoCollectionFields.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022. [恒宇少年 - 于起宇] 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 | * http://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 | package org.minbox.framework.logging.admin.storage.mongo; 18 | 19 | /** 20 | * The mongo collection fields 21 | * 22 | * @author 恒宇少年 23 | */ 24 | public interface MongoCollectionFields { 25 | String SERVICE_DETAIL_ID = "_id"; 26 | String SERVICE_ID = "serviceId"; 27 | String SERVICE_IP = "serviceIp"; 28 | String SERVICE_PORT = "servicePort"; 29 | String SERVICE_LAST_REPORT_TIME = "lastReportTime"; 30 | 31 | String LOG_CREATE_TIME = "createTime"; 32 | } 33 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/discovery/lb/LoadBalanceNode.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.admin.discovery.lb; 2 | 3 | /** 4 | * Load Balance Node 5 | * 6 | * @author 恒宇少年 7 | */ 8 | public class LoadBalanceNode { 9 | /** 10 | * node init weight 11 | */ 12 | private int initWeight = 1; 13 | /** 14 | * logging admin address 15 | */ 16 | private String address; 17 | /** 18 | * current weight 19 | */ 20 | private int currentWeight; 21 | 22 | public LoadBalanceNode(String address) { 23 | this.address = address; 24 | } 25 | 26 | public int getInitWeight() { 27 | return initWeight; 28 | } 29 | 30 | public void setInitWeight(int initWeight) { 31 | this.initWeight = initWeight; 32 | } 33 | 34 | public String getAddress() { 35 | return address; 36 | } 37 | 38 | public void setAddress(String address) { 39 | this.address = address; 40 | } 41 | 42 | public int getCurrentWeight() { 43 | return currentWeight; 44 | } 45 | 46 | public void setCurrentWeight(int currentWeight) { 47 | this.currentWeight = currentWeight; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/annotation/Endpoint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.core.annotation; 19 | 20 | import org.springframework.stereotype.Component; 21 | 22 | import java.lang.annotation.*; 23 | 24 | /** 25 | * ApiBoot Logging Endpoint Annotation 26 | * Only classes with this annotation will be scanned 27 | * 28 | * @author 恒宇少年 29 | */ 30 | @Target({ElementType.TYPE}) 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Documented 33 | @Component 34 | public @interface Endpoint { 35 | } 36 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/shortenClassname.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | export default (fullName, targetLength) => { 18 | if (!fullName || fullName.length < targetLength) { 19 | return fullName; 20 | } 21 | 22 | const tokens = fullName.split('.'); 23 | let shortened = tokens.pop(); 24 | while (tokens.length > 0) { 25 | const next = tokens.pop(); 26 | if (next.length + 1 + shortened.length < targetLength) { 27 | shortened = next + '.' + shortened; 28 | } else { 29 | shortened = next[0] + '.' + shortened; 30 | } 31 | } 32 | return shortened; 33 | }; 34 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: Ci Builder 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | branches: [ master,develop ] 10 | pull_request: 11 | branches: [ master,develop ] 12 | 13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 14 | jobs: 15 | # This workflow contains a single job called "build" 16 | build: 17 | # The type of runner that the job will run on 18 | runs-on: ubuntu-latest 19 | 20 | # Steps represent a sequence of tasks that will be executed as part of the job 21 | steps: 22 | # Checkout source code 23 | - uses: actions/checkout@v2 24 | # Install Java 1.8 25 | - uses: actions/setup-java@v1 26 | with: 27 | java-version: 1.8 28 | # Cache maven .m2 directory 29 | - uses: actions/cache@v2 30 | with: 31 | path: ~/.m2/repository 32 | key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} 33 | restore-keys: | 34 | ${{ runner.os }}-maven- 35 | # Publish to Apache Maven Central 36 | - run: mvn clean compile -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/index.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ApiBoot Logging Admin 28 | 29 | 30 | 31 |

32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/directives/sticks-below.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | const bind = (el, binding) => { 18 | if (!binding.value) { 19 | return; 20 | } 21 | const top = binding.value.map(v => document.querySelector(v)) 22 | .filter(v => Boolean(v)) 23 | .map(v => v.getBoundingClientRect().height) 24 | .reduce((a, b) => a + b, 0); 25 | el.style.top = `${top}px`; 26 | el.style.position = 'sticky'; 27 | }; 28 | 29 | export default { 30 | bind, 31 | update(el, binding) { 32 | if (binding.value === binding.oldValue) { 33 | return 34 | } 35 | bind(el, binding) 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/views/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | const views = []; 18 | 19 | /* global require */ 20 | const context = require.context('.', true, /^\.\/.+\/index\.(js|vue)$/); 21 | context.keys().forEach(function (key) { 22 | const defaultExport = context(key).default; 23 | if (defaultExport && defaultExport.install) { 24 | views.push(defaultExport) 25 | } 26 | }); 27 | 28 | export const VIEW_GROUP = { 29 | WEB: 'web', 30 | INSIGHTS: 'insights', 31 | DATA: 'data', 32 | JVM: 'jvm', 33 | LOGGING: 'logging', 34 | NONE: 'none', 35 | SECURITY: 'security' 36 | }; 37 | 38 | export default views; 39 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/notice/LoggingNotice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.notice; 19 | 20 | import org.minbox.framework.logging.core.MinBoxLog; 21 | import org.springframework.core.Ordered; 22 | 23 | /** 24 | * ApiBoot Logging Local Notice 25 | * 26 | * @author 恒宇少年 27 | */ 28 | public interface LoggingNotice extends Ordered { 29 | /** 30 | * Local Notice ApiBoot Log Instance 31 | * 32 | * @param minBoxLog Log object for each HTTP request 33 | */ 34 | void notice(MinBoxLog minBoxLog); 35 | } 36 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/span/LogSpanIdGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.span; 19 | 20 | 21 | import org.minbox.framework.logging.client.MinBoxLoggingException; 22 | 23 | /** 24 | * ApiBoot Logging Span 25 | * Create new spanId 26 | * 27 | * @author 恒宇少年 28 | */ 29 | public interface LogSpanIdGenerator { 30 | /** 31 | * create new spanId 32 | * 33 | * @return span id 34 | * @throws MinBoxLoggingException exception 35 | */ 36 | String createSpanId() throws MinBoxLoggingException; 37 | } 38 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging-samples 7 | org.minbox.framework 8 | ${revision} 9 | 10 | 4.0.0 11 | jar 12 | 13 | "minbox-logging" 客户端集成使用示例 14 | 15 | logging-client-sample 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 21 | 22 | org.minbox.framework 23 | minbox-logging-client 24 | 25 | 26 | org.minbox.framework 27 | minbox-logging-spring-context 28 | 29 | 30 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/mixins/subscribing.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 | export default { 18 | created() { 19 | this.subscribe(); 20 | }, 21 | beforeDestroy() { 22 | this.unsubscribe(); 23 | }, 24 | methods: { 25 | async subscribe() { 26 | if (!this.subscription) { 27 | this.subscription = await this.createSubscription(); 28 | } 29 | }, 30 | unsubscribe() { 31 | if (this.subscription) { 32 | try { 33 | !this.subscription.closed && this.subscription.unsubscribe(); 34 | } finally { 35 | this.subscription = null; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/report/retry/LoggingReportRetrySupport.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.admin.report.retry; 2 | 3 | import org.minbox.framework.logging.core.MinBoxLog; 4 | import org.springframework.beans.factory.DisposableBean; 5 | 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | /** 10 | * {@link LoggingReportRetry} Support 11 | * 12 | * @author 恒宇少年 13 | */ 14 | public class LoggingReportRetrySupport implements LoggingReportRetry, DisposableBean { 15 | /** 16 | * the bean name of {@link LoggingReportRetrySupport} 17 | */ 18 | public static final String BEAN_NAME = "loggingReportRetry"; 19 | /** 20 | * Log waiting for retry report 21 | */ 22 | private static final LinkedList LOGS = new LinkedList<>(); 23 | 24 | @Override 25 | public void addToRetryCollection(MinBoxLog minBoxLog) { 26 | LOGS.add(minBoxLog); 27 | } 28 | 29 | @Override 30 | public void addToRetryCollection(List minBoxLogs) { 31 | LOGS.addAll(minBoxLogs); 32 | } 33 | 34 | @Override 35 | public List getAllRetryLogs() { 36 | return LOGS; 37 | } 38 | 39 | @Override 40 | public void destroy() throws Exception { 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/views/wallboard/hex-mesh.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 * as hm from './hex-mesh'; 18 | 19 | describe('calcLayout', () => { 20 | 21 | it('should calculate optimum layout for 12 in 1594x879', () => { 22 | const result = hm.calcLayout(12, 1594, 879); 23 | 24 | expect(result).toEqual({ 25 | rows: 3, 26 | cols: 5, 27 | sideLength: 175.8 28 | }); 29 | }); 30 | 31 | it('should calculate optimum layout for 1 in 100x100', () => { 32 | const result = hm.calcLayout(1, 100, 100); 33 | 34 | expect(result).toEqual({ 35 | rows: 1, 36 | cols: 1, 37 | sideLength: 50 38 | }); 39 | }); 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /minbox-logging-admin/src/main/java/org/minbox/framework/logging/admin/storage/mongo/ServiceEntity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022. [恒宇少年 - 于起宇] 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 | * http://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 | package org.minbox.framework.logging.admin.storage.mongo; 18 | 19 | import lombok.AccessLevel; 20 | import lombok.Data; 21 | import lombok.NoArgsConstructor; 22 | 23 | import java.time.LocalDateTime; 24 | 25 | /** 26 | * The service mongo entity 27 | * 28 | * @author 恒宇少年 29 | */ 30 | @Data 31 | @NoArgsConstructor(access = AccessLevel.PACKAGE) 32 | class ServiceEntity { 33 | private String _id; 34 | private String serviceId; 35 | private String serviceIp; 36 | private int servicePort; 37 | private LocalDateTime lastReportTime; 38 | private LocalDateTime createTime = LocalDateTime.now(); 39 | } 40 | -------------------------------------------------------------------------------- /minbox-logging-admin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging-dependencies 7 | org.minbox.framework 8 | ${revision} 9 | ../minbox-logging-dependencies 10 | 11 | 4.0.0 12 | jar 13 | minbox-logging-admin 14 | 15 | 16 | org.minbox.framework 17 | minbox-logging-core 18 | ${project.version} 19 | 20 | 21 | org.springframework 22 | spring-webmvc 23 | true 24 | 25 | 26 | org.springframework.data 27 | spring-data-mongodb 28 | true 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /minbox-logging-admin/src/main/java/org/minbox/framework/logging/admin/storage/mongo/MongoCollectionNames.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022. [恒宇少年 - 于起宇] 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 | * http://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 | package org.minbox.framework.logging.admin.storage.mongo; 18 | 19 | /** 20 | * The mongo collection names with minbox logging 21 | * 22 | * @author 恒宇少年 23 | */ 24 | public interface MongoCollectionNames { 25 | /** 26 | * The {@link GlobalLogMongoEntity} storage collection name 27 | */ 28 | String GLOBAL_LOG = "minbox-global-logs"; 29 | /** 30 | * The {@link RequestLogMongoEntity} storage collection name 31 | */ 32 | String REQUEST_LOG = "minbox-request-logs"; 33 | /** 34 | * The {@link ServiceEntity} storage collection name 35 | */ 36 | String SERVICE = "minbox-services"; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/sba-config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 merge from 'lodash/merge'; 18 | 19 | const DEFAULT_CONFIG = { 20 | uiSettings: { 21 | brand: '', 22 | rememberMeEnabled: true, 23 | externalViews: [], 24 | favicon: 'assets/img/favicon.ico', 25 | faviconDanger: 'assets/img/favicon-danger.png', 26 | notificationFilterEnabled: false, 27 | routes: [], 28 | }, 29 | user: null, 30 | extensions: [], 31 | externalViews: [], 32 | csrf: { 33 | parameterName: '_csrf', 34 | headerName: 'X-XSRF-TOKEN' 35 | }, 36 | use: function (ext) { 37 | this.extensions.push(ext); 38 | } 39 | }; 40 | 41 | export default merge(DEFAULT_CONFIG, global.SBA) 42 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/tracer/LogTraceIdGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.tracer; 19 | 20 | import org.minbox.framework.logging.client.MinBoxLoggingException; 21 | import org.minbox.framework.logging.core.MinBoxLog; 22 | 23 | /** 24 | * ApiBoot Logging Tracer 25 | * Create new traceId 26 | * 27 | * @author 恒宇少年 28 | */ 29 | public interface LogTraceIdGenerator { 30 | /** 31 | * Create new traceId 32 | * 33 | * @return The Trace ID of http request {@link MinBoxLog#getTraceId()} 34 | * @throws MinBoxLoggingException exception 35 | */ 36 | String createTraceId() throws MinBoxLoggingException; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/directives/on-resize.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 ResizeObserver from 'resize-observer-polyfill'; 18 | 19 | const observers = new WeakMap(); 20 | 21 | const bind = (el, binding) => { 22 | unbind(el); 23 | const observer = new ResizeObserver(binding.value); 24 | observer.observe(el); 25 | observers.set(el, observer); 26 | 27 | }; 28 | 29 | const unbind = (el) => { 30 | const observer = observers.get(el); 31 | if (observer) { 32 | observer.disconnect(); 33 | observers.delete(el); 34 | } 35 | }; 36 | 37 | export default { 38 | bind, 39 | update(el, binding) { 40 | if (binding.value === binding.oldValue) { 41 | return 42 | } 43 | bind(el, binding) 44 | }, 45 | unbind 46 | } 47 | 48 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-tags.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 27 | 28 | 43 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-time-ago.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 moment from 'moment-shortformat'; 18 | 19 | export default { 20 | props: { 21 | date: { 22 | type: [String, Date, Number, moment], 23 | default: null 24 | } 25 | }, 26 | data: () => ({ 27 | now: moment(), 28 | timer: null, 29 | }), 30 | computed: { 31 | timeAgo() { 32 | return moment(this.date).short(true, this.now); 33 | } 34 | }, 35 | created() { 36 | this.timer = window.setInterval(() => { 37 | this.now = moment(); 38 | }, 1000); 39 | }, 40 | render() { 41 | return this._v(this.timeAgo); 42 | }, 43 | beforeDestroy() { 44 | if (this.timer) { 45 | window.clearInterval(this.timer); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/directives/popper.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 Popper from 'popper.js'; 18 | 19 | const poppers = new WeakMap(); 20 | 21 | const bind = (el, binding) => { 22 | const reference = typeof binding.value === 'string' ? document.getElementById(binding.value) : binding.value; 23 | if (reference) { 24 | const popper = new Popper(reference, el); 25 | poppers.set(el, popper); 26 | } 27 | }; 28 | 29 | const unbind = (el) => { 30 | const popper = poppers.get(el); 31 | if (popper) { 32 | popper.destroy(el); 33 | } 34 | }; 35 | 36 | export default { 37 | bind, 38 | update(el, binding) { 39 | if (binding.value === binding.oldValue) { 40 | return 41 | } 42 | bind(el, binding) 43 | }, 44 | unbind 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /minbox-logging-spring-context/src/main/java/org/minbox/framework/logging/spring/context/annotation/client/LoggingClientBeanDefinitionRegistrar.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.spring.context.annotation.client; 2 | 3 | import org.minbox.framework.logging.client.interceptor.web.LoggingWebInterceptor; 4 | import org.minbox.framework.logging.spring.util.LoggingBeanUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 8 | import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; 9 | import org.springframework.core.type.AnnotationMetadata; 10 | 11 | /** 12 | * Register logging client beans {@link org.minbox.framework.logging.spring.util.LoggingBeanUtils#registerLoggingClientBeans(BeanDefinitionRegistry)} 13 | * register {@link LoggingWebInterceptor} 14 | * 15 | * @author 恒宇少年 16 | */ 17 | public class LoggingClientBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { 18 | /** 19 | * logger instance 20 | */ 21 | static Logger logger = LoggerFactory.getLogger(LoggingClientBeanDefinitionRegistrar.class); 22 | 23 | @Override 24 | public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 25 | LoggingBeanUtils.registerLoggingClientBeans(registry); 26 | logger.info("Logging client beans register successfully."); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/store.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 Application from '@/services/application'; 18 | import {EMPTY} from '@/utils/rxjs'; 19 | import Store from './store'; 20 | 21 | jest.mock('@/services/application'); 22 | jest.setTimeout(500); 23 | 24 | describe('store', () => { 25 | describe('given no registered applications', function () { 26 | Application.list = jest.fn(() => EMPTY); 27 | 28 | it('it should emit a connected event after start', async () => { 29 | const store = new Store(); 30 | 31 | const connectedEvent = new Promise(resolve => { 32 | store.addEventListener('connected', resolve) 33 | }); 34 | 35 | store.start(); 36 | await connectedEvent; 37 | store.stop(); 38 | }); 39 | 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/autolink.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 _Autolinker from 'autolinker'; 18 | 19 | export const defaults = { 20 | urls: { 21 | schemeMatches: true, 22 | wwwMatches: false, 23 | tldMatches: false 24 | }, 25 | email: false, 26 | phone: false, 27 | mention: false, 28 | hashtag: false, 29 | 30 | stripPrefix: false, 31 | stripTrailingSlash: false, 32 | newWindow: true, 33 | 34 | truncate: { 35 | length: 0, 36 | location: 'smart' 37 | }, 38 | 39 | className: '' 40 | }; 41 | const autolinker = new _Autolinker(defaults); 42 | 43 | export default s => autolinker.link(s); 44 | export function Autolink(cfg) { 45 | this.autolinker = new _Autolinker({...defaults, ...cfg}); 46 | return s => this.autolinker.link(s) 47 | } 48 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/notice/LoggingNoticeEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.notice; 19 | 20 | import lombok.Getter; 21 | import org.minbox.framework.logging.core.MinBoxLog; 22 | import org.springframework.context.ApplicationEvent; 23 | 24 | /** 25 | * ApiBoot Logging Notice Event 26 | * Log objects can be obtained by listening for this event 27 | * 28 | * @author 恒宇少年 29 | */ 30 | @Getter 31 | public class LoggingNoticeEvent extends ApplicationEvent { 32 | /** 33 | * ApiBoot Logging Object 34 | */ 35 | private MinBoxLog log; 36 | 37 | public LoggingNoticeEvent(Object source, MinBoxLog log) { 38 | super(source); 39 | this.log = log; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-formatted-obj.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 44 | 45 | 50 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/axios.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 | import sbaConfig from '@/sba-config' 17 | import axios from 'axios'; 18 | 19 | axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 20 | axios.defaults.xsrfHeaderName = sbaConfig.csrf.headerName; 21 | 22 | export const redirectOn401 = (predicate = () => true) => error => { 23 | if (error.response && error.response.status === 401 && predicate(error)) { 24 | window.location.assign(`login?redirectTo=${encodeURIComponent(window.location.href)}`); 25 | } 26 | return Promise.reject(error); 27 | 28 | }; 29 | 30 | const instance = axios.create({headers: {'Accept': 'application/json'}}); 31 | instance.interceptors.response.use(response => response, redirectOn401()); 32 | instance.create = axios.create; 33 | 34 | export default instance; 35 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-admin-sample/src/main/java/org/minbox/framework/logging/admin/sample/LoggingAdminConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.admin.sample; 2 | 3 | import org.minbox.framework.logging.admin.LoggingAdminFactoryBean; 4 | import org.minbox.framework.logging.admin.storage.LoggingDataSourceStorage; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import javax.sql.DataSource; 9 | 10 | /** 11 | * @author:恒宇少年 - 于起宇 12 | *

13 | * DateTime:2019/9/14 8:31 下午 14 | * Blog:http://blog.yuqiyu.com 15 | * WebSite:http://www.jianshu.com/u/092df3f77bca 16 | * Gitee:https://gitee.com/hengboy 17 | * GitHub:https://github.com/hengboy 18 | */ 19 | @Configuration 20 | public class LoggingAdminConfiguration { 21 | 22 | /** 23 | * 当bean容器内存在{@link DataSource}对象实例时创建{@link LoggingAdminFactoryBean}示例 24 | * 25 | * @param dataSource {@link DataSource} 26 | * @return {@link LoggingAdminFactoryBean} 27 | */ 28 | @Bean 29 | public LoggingAdminFactoryBean dataSourceLoggingAdminFactoryBean(DataSource dataSource) { 30 | LoggingAdminFactoryBean adminFactoryBean = new LoggingAdminFactoryBean(); 31 | adminFactoryBean.setShowConsoleReportLog(true); 32 | adminFactoryBean.setFormatConsoleLogJson(true); 33 | adminFactoryBean.setLoggingStorage(new LoggingDataSourceStorage(dataSource)); 34 | return adminFactoryBean; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/discovery/lb/support/DefaultLoadBalanceStrategy.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.admin.discovery.lb.support; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | import org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceNode; 5 | import org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceStrategy; 6 | import org.springframework.util.ObjectUtils; 7 | 8 | import java.util.Arrays; 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | /** 13 | * The {@link LoadBalanceStrategy} default support 14 | * 15 | * @author 恒宇少年 16 | * @see LoadBalanceNode 17 | */ 18 | public abstract class DefaultLoadBalanceStrategy implements LoadBalanceStrategy { 19 | 20 | /** 21 | * Initialize the list of transformation nodes 22 | * Convert admin address to {@link LoadBalanceNode} 23 | * 24 | * @param adminAddress logging admin address array 25 | * @return {@link LoadBalanceNode} collection 26 | */ 27 | protected List initNodeList(String[] adminAddress) { 28 | if (ObjectUtils.isEmpty(adminAddress)) { 29 | throw new MinBoxLoggingException("Admin address not configured."); 30 | } 31 | List nodes = new LinkedList(); 32 | Arrays.stream(adminAddress).forEach(address -> nodes.add(new LoadBalanceNode(address))); 33 | return nodes; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/shortenClassname.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 shortenClassname from './shortenClassname'; 18 | 19 | describe('shortenClassname', () => { 20 | 21 | it('should shorten when too long', () => { 22 | expect(shortenClassname('de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration', 40)).toBe('d.c.b.a.s.config.AdminServerAutoConfiguration') 23 | }); 24 | 25 | it('should not shorten when string is small enough', () => { 26 | expect(shortenClassname('de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration', 300)).toBe('de.codecentric.boot.admin.server.config.AdminServerAutoConfiguration') 27 | }); 28 | 29 | it('should not shorten when no package is present', () => { 30 | expect(shortenClassname('AdminServerAutoConfiguration', 1)).toBe('AdminServerAutoConfiguration') 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/discovery/support/LoggingAbstractAdminDiscovery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.admin.discovery.support; 19 | 20 | import org.minbox.framework.logging.client.admin.discovery.LoggingAdminDiscovery; 21 | 22 | import java.util.Base64; 23 | 24 | /** 25 | * ApiBoot Logging Abstract Admin Discovery 26 | * 27 | * @author 恒宇少年 28 | */ 29 | public abstract class LoggingAbstractAdminDiscovery implements LoggingAdminDiscovery { 30 | /** 31 | * get basic auth base64 string 32 | * 33 | * @param basicInfo basic info 34 | * @return basic auth base64 string 35 | */ 36 | protected String getBasicBase64(String basicInfo) { 37 | return Base64.getEncoder().encodeToString(basicInfo.getBytes()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/objToString.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 objToString from './objToString' 18 | 19 | describe('objToString should', () => { 20 | 21 | it('return the input string for normal text', () => { 22 | const obj = { 23 | a: 'start', 24 | b: 1, 25 | c: true, 26 | d: [1, 2, [3, 4]], 27 | e: { 28 | f: '', 29 | g: 1, 30 | h: null, 31 | i: undefined, 32 | j: {}, 33 | k: [1], 34 | l: [{a:1, b:'foo'}, {b:2}] 35 | } 36 | }; 37 | const str = `a: start 38 | b: 1 39 | c: true 40 | d: 41 | - 1 42 | - 2 43 | - 44 | - 3 45 | - 4 46 | e: 47 | f: 48 | g: 1 49 | h: null 50 | i: 51 | j: {} 52 | k: 53 | - 1 54 | l: 55 | - 56 | a: 1 57 | b: foo 58 | - 59 | b: 2`; 60 | expect(objToString(obj)).toBe(str); 61 | }); 62 | 63 | }); 64 | -------------------------------------------------------------------------------- /minbox-logging-admin/src/main/java/org/minbox/framework/logging/admin/event/ReportLogEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.admin.event; 19 | 20 | import lombok.Getter; 21 | import org.minbox.framework.logging.core.LoggingClientNotice; 22 | import org.springframework.context.ApplicationEvent; 23 | 24 | /** 25 | * The time of publication after receiving the reported log information 26 | * 27 | * @author 恒宇少年 28 | * @see org.minbox.framework.logging.admin.endpoint.LoggingEndpoint 29 | */ 30 | @Getter 31 | public class ReportLogEvent extends ApplicationEvent { 32 | /** 33 | * ApiBoot Log Client Report Notice Object 34 | */ 35 | private LoggingClientNotice logClientNotice; 36 | 37 | public ReportLogEvent(Object source, LoggingClientNotice logClientNotice) { 38 | super(source); 39 | this.logClientNotice = logClientNotice; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/global/GlobalLoggingThreadLocal.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.global; 2 | 3 | import com.alibaba.ttl.TransmittableThreadLocal; 4 | import org.minbox.framework.logging.core.GlobalLog; 5 | import org.springframework.util.ObjectUtils; 6 | 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | /** 11 | * Use threadLocal to store all GlobalLogs in a request that need to be saved 12 | * 13 | * @author 恒宇少年 14 | */ 15 | public class GlobalLoggingThreadLocal { 16 | /** 17 | * GlobalLog {@link ThreadLocal} define 18 | */ 19 | private static final TransmittableThreadLocal> GLOBAL_LOGS = new TransmittableThreadLocal(); 20 | 21 | /** 22 | * Get {@link GlobalLog} List from ThreadLocal 23 | * 24 | * @return {@link GlobalLog} 25 | */ 26 | public static List getGlobalLogs() { 27 | return GLOBAL_LOGS.get(); 28 | } 29 | 30 | /** 31 | * Add {@link GlobalLog} to ThreadLocal 32 | * 33 | * @param globalLog {@link GlobalLog} 34 | */ 35 | public static void addGlobalLogs(GlobalLog globalLog) { 36 | List globalLogs = getGlobalLogs(); 37 | if (ObjectUtils.isEmpty(globalLogs)) { 38 | globalLogs = new LinkedList(); 39 | } 40 | globalLogs.add(globalLog); 41 | GLOBAL_LOGS.set(globalLogs); 42 | } 43 | 44 | /** 45 | * Delete {@link GlobalLog} list in ThreadLocal 46 | */ 47 | public static void remove() { 48 | GLOBAL_LOGS.remove(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/tracer/support/DefaultLogTraceIdGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.tracer.support; 19 | 20 | import org.minbox.framework.logging.client.MinBoxLoggingException; 21 | import org.minbox.framework.logging.client.tracer.LogTraceIdGenerator; 22 | import org.minbox.framework.logging.core.MinBoxLog; 23 | 24 | import java.util.UUID; 25 | 26 | /** 27 | * The default support of {@link LogTraceIdGenerator} 28 | * 29 | * @author 恒宇少年 30 | */ 31 | public class DefaultLogTraceIdGenerator implements LogTraceIdGenerator { 32 | /** 33 | * Use UUID as the default traceId 34 | * 35 | * @return {@link MinBoxLog#getTraceId()} 36 | * @throws MinBoxLoggingException Exception 37 | */ 38 | @Override 39 | public String createTraceId() throws MinBoxLoggingException { 40 | return UUID.randomUUID().toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-time-ago.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 {shallowMount} from '@vue/test-utils'; 18 | import moment from 'moment'; 19 | import sbaTimeAgo from './sba-time-ago.js'; 20 | 21 | moment.now = () => +new Date(1318781879406); 22 | 23 | describe('time-ago', () => { 24 | 25 | describe('given a short time passed time', () => { 26 | it('should match the snapshot', () => { 27 | const wrapper = shallowMount(sbaTimeAgo, { 28 | propsData: { 29 | date: moment(1318781000000).utc() 30 | } 31 | }); 32 | expect(wrapper.vm.$el).toMatchSnapshot(); 33 | }); 34 | }); 35 | 36 | describe('given a long time passed time', () => { 37 | it('should match the snapshot', () => { 38 | const wrapper = shallowMount(sbaTimeAgo, { 39 | propsData: { 40 | date: moment(1310000000000).utc() 41 | } 42 | }); 43 | expect(wrapper.vm.$el).toMatchSnapshot(); 44 | }); 45 | }); 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/report/LoggingAdminReport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.admin.report; 19 | 20 | import org.minbox.framework.logging.client.MinBoxLoggingException; 21 | import org.minbox.framework.logging.core.MinBoxLog; 22 | 23 | import java.util.List; 24 | 25 | /** 26 | * Batch Report Request Logs To Admin 27 | * 28 | * @author 恒宇少年 29 | */ 30 | public interface LoggingAdminReport { 31 | /** 32 | * Report Request Logs To Admin 33 | * Loading a specified number of logs from the cache 34 | * 35 | * @throws MinBoxLoggingException Logging Exception 36 | */ 37 | void report() throws MinBoxLoggingException; 38 | 39 | /** 40 | * Report Specified Request Logs 41 | * 42 | * @param logs Request Logs 43 | * @throws MinBoxLoggingException Logging Exception 44 | */ 45 | void report(List logs) throws MinBoxLoggingException; 46 | } 47 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/span/support/DefaultLogSpanIdGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.span.support; 19 | 20 | 21 | import org.minbox.framework.logging.client.MinBoxLoggingException; 22 | import org.minbox.framework.logging.client.span.LogSpanIdGenerator; 23 | import org.minbox.framework.logging.core.MinBoxLog; 24 | 25 | import java.util.UUID; 26 | 27 | /** 28 | * ApiBoot Logging Default Span 29 | * Use By Create New SpanId 30 | * 31 | * @author 恒宇少年 32 | */ 33 | public class DefaultLogSpanIdGenerator implements LogSpanIdGenerator { 34 | /** 35 | * Create New SpanId 36 | * Use random uuid as default spanId 37 | * 38 | * @return {@link MinBoxLog#getSpanId()} 39 | * @throws MinBoxLoggingException Exception 40 | */ 41 | @Override 42 | public String createSpanId() throws MinBoxLoggingException { 43 | return UUID.randomUUID().toString(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/i18n/i18n.zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "server_connection_failed": "Server connection failed. " 4 | }, 5 | "log": { 6 | "title": "链路日志列表", 7 | "top-menu": "链路日志", 8 | "time": "请求时间", 9 | "traceId": "链路编号", 10 | "uri": "请求日志", 11 | "status": "响应状态", 12 | "method": "请求方式", 13 | "serviceId": "服务ID", 14 | "consumeTime": "耗时(ms)" 15 | }, 16 | "services": { 17 | "top-menu": "日志服务", 18 | "title": "服务列表", 19 | "id": "服务ID", 20 | "ip": "服务IP", 21 | "port": "服务端口号", 22 | "lastReportTime": "最后上报时间", 23 | "createTime": "首次上报时间" 24 | }, 25 | "term": { 26 | "application": "Application", 27 | "attributes": "Attributes", 28 | "bytes": "Bytes", 29 | "cancel": "Cancel", 30 | "clear": "Clear", 31 | "cleared": "Cleared", 32 | "close": "Close", 33 | "confirm": "Confirm", 34 | "delete": "Delete", 35 | "deleted": "Deleted", 36 | "duration": "Duration", 37 | "event": "Event", 38 | "ever": "ever", 39 | "executing": "Executing...", 40 | "execution_failed": "Execution failed.", 41 | "execution_successful": "Execution successful.", 42 | "failed": "Failed", 43 | "float": "Float", 44 | "hours": "{count} hour | {count} hours", 45 | "instances": "Instances", 46 | "integer": "Integer", 47 | "milliseconds": "Milliseconds", 48 | "minutes": "{count} minute | {count} minutes", 49 | "name": "Name", 50 | "operations": "Operations", 51 | "save": "Save", 52 | "stacktrace": "Stacktrace", 53 | "suppress": "Suppress", 54 | "time": "Time", 55 | "unsuppress": "Unsuppress", 56 | "username": "Username" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/discovery/LoggingAdminDiscovery.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.admin.discovery; 19 | 20 | import org.minbox.framework.logging.client.MinBoxLoggingException; 21 | 22 | /** 23 | * Look Up ApiBoot Logging Admin Service Urls 24 | * 1. single api-boot-logging-admin service 25 | * 2. pull api-boot-logging-admin services from registry center 26 | * 27 | * @author 恒宇少年 28 | */ 29 | public interface LoggingAdminDiscovery { 30 | /** 31 | * lookup a api-boot-logging-admin service url 32 | * 33 | * @return service url 34 | * @throws MinBoxLoggingException Logging Exception 35 | */ 36 | String lookup() throws MinBoxLoggingException; 37 | 38 | /** 39 | * get basic auth info 40 | * if config spring security user 41 | * 42 | * @return spring security user info 43 | * @throws MinBoxLoggingException Logging Exception 44 | */ 45 | String getBasicAuth() throws MinBoxLoggingException; 46 | } 47 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/assets/css/_utilities.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright 2014-2018 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 | * http://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 | // Import the initial variables 17 | @import "~bulma/sass/utilities/initial-variables"; 18 | @import "~bulma/sass/utilities/functions"; 19 | 20 | //$turquoise: rgb(66, 211, 165); 21 | $turquoise: #78a744; 22 | // overrides 23 | $primary: $turquoise; 24 | $primary-invert: $white; 25 | 26 | // Add new color variables to the color map. 27 | @import "~bulma/sass/utilities/derived-variables.sass"; 28 | 29 | $addColors: (); 30 | $colors: map-merge($colors, $addColors); 31 | 32 | $link: $primary; 33 | 34 | $modal-card-head-background-color: $white; 35 | $modal-content-width: calc(100vh - 40px); 36 | 37 | $navbar-background-color: $black-ter; 38 | $navbar-item-color: $grey; 39 | $navbar-item-hover-color: $white; 40 | $navbar-item-hover-background-color: $navbar-background-color; 41 | $navbar-item-active-color: $white; 42 | $navbar-item-active-background-color: $navbar-background-color; 43 | 44 | @import "~bulma/sass/utilities/mixins.sass"; 45 | 46 | // for calculations / originally rem 47 | $navbar-height-px: 52px; 48 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/global/GlobalLogging.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.global; 2 | 3 | /** 4 | * Global log collection interface 5 | * Provide debug, info, and error log collection 6 | * 7 | * @author 恒宇少年 8 | */ 9 | public interface GlobalLogging { 10 | /** 11 | * Collect Debug Level Logs 12 | * 13 | * @param msg log content 14 | */ 15 | void debug(String msg); 16 | 17 | /** 18 | * Collect Debug Level Logs 19 | * 20 | * @param format Unformatted log content 21 | * @param arguments List of parameters corresponding to log content 22 | */ 23 | void debug(String format, Object... arguments); 24 | 25 | /** 26 | * Collect Info Level Logs 27 | * 28 | * @param msg log content 29 | */ 30 | void info(String msg); 31 | 32 | /** 33 | * Collect Info Level Logs 34 | * 35 | * @param format Unformatted log content 36 | * @param arguments List of parameters corresponding to log content 37 | */ 38 | void info(String format, Object... arguments); 39 | 40 | /** 41 | * Collect Error Level Logs 42 | * 43 | * @param msg log content 44 | */ 45 | void error(String msg); 46 | 47 | /** 48 | * Collect Error Level Logs 49 | * 50 | * @param msg log content 51 | * @param throwable Exception object instance 52 | */ 53 | void error(String msg, Throwable throwable); 54 | 55 | /** 56 | * Collect Error Level Logs 57 | * 58 | * @param format Unformatted log content 59 | * @param arguments List of parameters corresponding to log content 60 | */ 61 | void error(String format, Object... arguments); 62 | } 63 | -------------------------------------------------------------------------------- /minbox-logging-spring-context/src/main/java/org/minbox/framework/logging/spring/context/annotation/admin/LoggingAdminBeanDefinitionRegistrar.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.spring.context.annotation.admin; 2 | 3 | import org.minbox.framework.logging.spring.util.LoggingBeanUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 7 | import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; 8 | import org.springframework.core.type.AnnotationMetadata; 9 | 10 | /** 11 | * Register logging admin beans{@link LoggingBeanUtils#registerLoggingAdminBeans(BeanDefinitionRegistry)} 12 | * register {@link org.minbox.framework.logging.admin.storage.LoggingDataSourceStorage} 13 | * register {@link org.minbox.framework.logging.admin.listener.ReportLogStorageListener} 14 | * register {@link org.minbox.framework.logging.admin.listener.ReportLogJsonFormatListener} 15 | * register {@link org.minbox.framework.logging.admin.endpoint.LoggingEndpoint} 16 | * 17 | * @author 恒宇少年 18 | */ 19 | public class LoggingAdminBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { 20 | /** 21 | * logger instance 22 | */ 23 | static Logger logger = LoggerFactory.getLogger(LoggingAdminBeanDefinitionRegistrar.class); 24 | 25 | @Override 26 | public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 27 | LoggingBeanUtils.registerLoggingAdminBeans(registry); 28 | logger.info("Logging admin beans register successfully."); 29 | LoggingBeanUtils.registerLoggingAdminUiBeans(registry); 30 | logger.info("Logging admin ui beans register successfully."); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-admin-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging-samples 7 | org.minbox.framework 8 | ${revision} 9 | 10 | 4.0.0 11 | jar 12 | logging-admin-sample 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-web 17 | 18 | 19 | org.minbox.framework 20 | minbox-logging-admin 21 | 22 | 23 | org.minbox.framework 24 | minbox-logging-admin-ui 25 | 26 | 27 | org.minbox.framework 28 | minbox-logging-spring-context 29 | 30 | 31 | mysql 32 | mysql-connector-java 33 | 34 | 35 | com.zaxxer 36 | HikariCP 37 | 38 | 39 | org.minbox.framework 40 | api-boot-starter-mybatis-enhance 41 | 42 | 43 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/notice/support/LoggingLocalNotice.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.notice.support; 2 | 3 | import org.minbox.framework.logging.client.LoggingFactoryBean; 4 | import org.minbox.framework.logging.client.notice.LoggingNotice; 5 | import org.minbox.framework.logging.core.MinBoxLog; 6 | import org.minbox.framework.util.JsonUtils; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * Local console log notification 12 | * 13 | * @author 恒宇少年 14 | */ 15 | public class LoggingLocalNotice implements LoggingNotice { 16 | /** 17 | * the bean name of {@link LoggingLocalNotice} 18 | */ 19 | public static final String BEAN_NAME = "loggingLocalNotice"; 20 | /** 21 | * logger instance 22 | */ 23 | static Logger logger = LoggerFactory.getLogger(LoggingLocalNotice.class); 24 | /** 25 | * Logging factory bean {@link LoggingFactoryBean} 26 | */ 27 | private LoggingFactoryBean loggingFactoryBean; 28 | 29 | public LoggingLocalNotice(LoggingFactoryBean loggingFactoryBean) { 30 | this.loggingFactoryBean = loggingFactoryBean; 31 | } 32 | 33 | /** 34 | * Output formatted log information according to configuration in console 35 | * {@link LoggingNotice} 36 | * 37 | * @param minBoxLog ApiBoot Log 38 | */ 39 | @Override 40 | public void notice(MinBoxLog minBoxLog) { 41 | if (loggingFactoryBean.isShowConsoleLog()) { 42 | logger.debug("Request Uri:{}, Logging:\n{}", minBoxLog.getRequestUri(), 43 | loggingFactoryBean.isFormatConsoleLog() ? JsonUtils.beautifyJson(minBoxLog) : JsonUtils.toJsonString(minBoxLog)); 44 | } 45 | } 46 | 47 | @Override 48 | public int getOrder() { 49 | return HIGHEST_PRECEDENCE; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-icon-button.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | 41 | 42 | 74 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/GlobalLog.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.core; 2 | 3 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 4 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 5 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; 6 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; 7 | import lombok.Data; 8 | 9 | import java.io.Serializable; 10 | import java.time.LocalDateTime; 11 | 12 | /** 13 | * Global log data entity 14 | * 15 | * @author 恒宇少年 16 | */ 17 | @Data 18 | public class GlobalLog implements Serializable { 19 | /** 20 | * The request log id 21 | */ 22 | private String requestLogId; 23 | /** 24 | * Global log level 25 | * {@link GlobalLogLevel} 26 | */ 27 | private GlobalLogLevel level; 28 | /** 29 | * all level's log content 30 | */ 31 | private String content; 32 | /** 33 | * Error stack information collected in error level logs 34 | */ 35 | private String exceptionStack; 36 | /** 37 | * caller class name 38 | * {@link StackTraceElement#getClassName()} 39 | */ 40 | private String callerClass; 41 | /** 42 | * caller method name 43 | * {@link StackTraceElement#getMethodName()} 44 | */ 45 | private String callerMethod; 46 | /** 47 | * caller code line number 48 | * {@link StackTraceElement#getLineNumber()} 49 | */ 50 | private int callerCodeLineNumber; 51 | /** 52 | * the global log create time 53 | * default is current time millis 54 | */ 55 | /** 56 | * The request logs create time 57 | */ 58 | @JsonSerialize(using = LocalDateTimeSerializer.class) 59 | @JsonDeserialize(using = LocalDateTimeDeserializer.class) 60 | private LocalDateTime createTime = LocalDateTime.now(); 61 | } 62 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/interceptor/LoggingAbstractInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.interceptor; 2 | 3 | import org.minbox.framework.logging.client.LoggingFactoryBean; 4 | import org.minbox.framework.logging.client.span.LogSpanIdGenerator; 5 | import org.minbox.framework.logging.client.span.support.DefaultLogSpanIdGenerator; 6 | import org.minbox.framework.logging.client.tracer.LogTraceIdGenerator; 7 | import org.minbox.framework.logging.client.tracer.support.DefaultLogTraceIdGenerator; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * The {@link LoggingInterceptor} basic support 13 | * 14 | * @author 恒宇少年 15 | */ 16 | public class LoggingAbstractInterceptor implements LoggingInterceptor { 17 | /** 18 | * logger instance 19 | */ 20 | static Logger logger = LoggerFactory.getLogger(LoggingAbstractInterceptor.class); 21 | /** 22 | * logging factory bean 23 | * {@link LoggingFactoryBean} 24 | */ 25 | private LoggingFactoryBean factoryBean; 26 | 27 | public LoggingAbstractInterceptor(LoggingFactoryBean factoryBean) { 28 | this.factoryBean = factoryBean; 29 | } 30 | 31 | public LoggingFactoryBean getFactoryBean() { 32 | return factoryBean; 33 | } 34 | 35 | /** 36 | * create new traceId {@link LogTraceIdGenerator} 37 | * 38 | * @return traceId 39 | * @see DefaultLogTraceIdGenerator 40 | */ 41 | @Override 42 | public String createTraceId() { 43 | return factoryBean.getTraceGenerator().createTraceId(); 44 | } 45 | 46 | /** 47 | * create new spanId {@link LogSpanIdGenerator} 48 | * 49 | * @return spanId 50 | * @see DefaultLogSpanIdGenerator 51 | */ 52 | @Override 53 | public String createSpanId() { 54 | return factoryBean.getSpanGenerator().createSpanId(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-confirm-button.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 25 | 26 | 52 | 53 | 54 | 61 | -------------------------------------------------------------------------------- /minbox-logging-spring-context/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging-dependencies 7 | org.minbox.framework 8 | ${revision} 9 | ../minbox-logging-dependencies 10 | 11 | 4.0.0 12 | jar 13 | minbox-logging-spring-context 14 | 15 | 16 | org.springframework 17 | spring-webmvc 18 | true 19 | 20 | 21 | javax.servlet 22 | javax.servlet-api 23 | true 24 | 25 | 26 | org.minbox.framework 27 | minbox-logging-admin 28 | true 29 | 30 | 31 | org.minbox.framework 32 | minbox-logging-admin-ui 33 | true 34 | 35 | 36 | org.minbox.framework 37 | minbox-logging-client 38 | true 39 | 40 | 41 | org.apache.commons 42 | commons-lang3 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /minbox-logging-dependencies/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging 7 | org.minbox.framework 8 | ${revision} 9 | 10 | 4.0.0 11 | pom 12 | minbox-logging-dependencies 13 | 14 | 15 | 16 | org.minbox.framework 17 | minbox-logging-client 18 | ${project.version} 19 | 20 | 21 | org.minbox.framework 22 | minbox-logging-admin 23 | ${project.version} 24 | 25 | 26 | org.minbox.framework 27 | minbox-logging-admin-ui 28 | ${project.version} 29 | 30 | 31 | org.minbox.framework 32 | minbox-logging-core 33 | ${project.version} 34 | 35 | 36 | org.minbox.framework 37 | minbox-logging-spring-context 38 | ${project.version} 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/objToString.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 isEmpty from 'lodash/isEmpty'; 18 | import isObject from 'lodash/isObject'; 19 | 20 | const nonEmptyComplexValue = value => (Array.isArray(value) || isObject(value)) && !isEmpty(value); 21 | 22 | const objToString = (obj, indent = '') => { 23 | if (Array.isArray(obj)) { 24 | if (isEmpty(obj)) { 25 | return indent + '[]'; 26 | } 27 | 28 | return obj.map(value => { 29 | if (nonEmptyComplexValue(value)) { 30 | return `${indent}-\n${objToString(value, indent + ' ')}`; 31 | } 32 | return `${indent}- ${objToString(value, '')}`; 33 | }).join('\n'); 34 | } 35 | 36 | if (isObject(obj)) { 37 | if (isEmpty(obj)) { 38 | return indent + '{}'; 39 | } 40 | 41 | return Object.entries(obj) 42 | .map(([key, value]) => { 43 | if (nonEmptyComplexValue(value)) { 44 | return `${indent}${key}:\n${objToString(value, indent + ' ')}`; 45 | } 46 | return `${indent}${key}: ${objToString(value, '')}`; 47 | }) 48 | .join('\n'); 49 | } 50 | 51 | if (obj === null) { 52 | return indent + 'null'; 53 | } 54 | 55 | if (typeof obj === 'undefined' || obj === '') { 56 | return ''; 57 | } 58 | 59 | return indent + obj; 60 | }; 61 | 62 | export default objToString; 63 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/report/LoggingReportScheduled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.admin.report; 19 | 20 | import org.minbox.framework.logging.client.LoggingFactoryBean; 21 | 22 | import java.util.concurrent.ScheduledExecutorService; 23 | import java.util.concurrent.ScheduledThreadPoolExecutor; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | /** 27 | * ApiBoot Logging Report Scheduled 28 | * 29 | * @author 恒宇少年 30 | */ 31 | public class LoggingReportScheduled { 32 | /** 33 | * the bean name of {@link LoggingReportScheduled} 34 | */ 35 | public static final String BEAN_NAME = "loggingReportScheduled"; 36 | /** 37 | * Scheduled Executor Service 38 | */ 39 | private static final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(10); 40 | 41 | /** 42 | * Scheduled Report 43 | * 44 | * @param factoryBean logging factory bean 45 | */ 46 | public LoggingReportScheduled(LoggingFactoryBean factoryBean) { 47 | // scheduled report request logs 48 | executorService.scheduleAtFixedRate(() -> factoryBean.getLoggingAdminReport().report(), 49 | factoryBean.getReportInitialDelaySecond(), factoryBean.getReportIntervalSecond(), TimeUnit.SECONDS); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-admin-sample/src/main/java/org/minbox/framework/logging/admin/sample/CustomerReportEventListener.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.admin.sample; 2 | 3 | import org.minbox.framework.logging.admin.event.ReportLogEvent; 4 | import org.minbox.framework.logging.core.LoggingClientNotice; 5 | import org.minbox.framework.logging.core.MinBoxLog; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.context.ApplicationEvent; 9 | import org.springframework.context.event.SmartApplicationListener; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * 自定义上报日志事件{@link ReportLogEvent}监听 16 | * 17 | * @author 恒宇少年 18 | */ 19 | @Component 20 | public class CustomerReportEventListener implements SmartApplicationListener { 21 | /** 22 | * logger instance 23 | */ 24 | static Logger logger = LoggerFactory.getLogger(CustomerReportEventListener.class); 25 | 26 | /** 27 | * 判断事件类型为{@link ReportLogEvent} 28 | * 29 | * @param eventType 30 | * @return 31 | */ 32 | @Override 33 | public boolean supportsEventType(Class eventType) { 34 | return ReportLogEvent.class == eventType; 35 | } 36 | 37 | /** 38 | * 自定义处理业务 39 | * Client一次可上报多条日志{@link MinBoxLog}信息 40 | * 41 | * @param event {@link ReportLogEvent} 42 | */ 43 | @Override 44 | public void onApplicationEvent(ApplicationEvent event) { 45 | ReportLogEvent reportLogEvent = (ReportLogEvent) event; 46 | LoggingClientNotice loggingClientNotice = reportLogEvent.getLogClientNotice(); 47 | 48 | // MinBoxLog 日志列表 49 | List logs = loggingClientNotice.getLoggers(); 50 | 51 | logger.debug("上报日志服务:{},IP地址:{},端口号:{},日志列表:", loggingClientNotice.getClientServiceId(), 52 | loggingClientNotice.getClientServiceIp(), 53 | loggingClientNotice.getClientServicePort(), 54 | logs); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/shell/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 23 | 24 | 61 | -------------------------------------------------------------------------------- /minbox-logging-admin/src/main/java/org/minbox/framework/logging/admin/storage/LoggingDefaultStorage.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.admin.storage; 2 | 3 | import org.minbox.framework.logging.core.GlobalLog; 4 | import org.minbox.framework.logging.core.MinBoxLog; 5 | import org.minbox.framework.logging.core.response.LoggingResponse; 6 | import org.minbox.framework.logging.core.response.ServiceResponse; 7 | 8 | import java.sql.SQLException; 9 | import java.time.LocalDateTime; 10 | import java.util.List; 11 | 12 | /** 13 | * The {@link LoggingStorage} default support 14 | * 15 | * @author 恒宇少年 16 | */ 17 | public class LoggingDefaultStorage implements LoggingStorage { 18 | @Override 19 | public String insertGlobalLog(String requestLogId, GlobalLog log) throws SQLException { 20 | return null; 21 | } 22 | 23 | @Override 24 | public String insertLog(String serviceDetailId, MinBoxLog log) throws SQLException { 25 | return null; 26 | } 27 | 28 | @Override 29 | public String insertServiceDetail(String serviceId, String serviceIp, int servicePort) throws SQLException { 30 | return null; 31 | } 32 | 33 | @Override 34 | public String selectServiceDetailId(String serviceId, String serviceIp, int servicePort) throws SQLException { 35 | return null; 36 | } 37 | 38 | @Override 39 | public List findAllService() throws SQLException { 40 | return null; 41 | } 42 | 43 | @Override 44 | public List findTopList(int topCount) throws SQLException { 45 | return null; 46 | } 47 | 48 | @Override 49 | public void updateLastReportTime(String serviceDetailId) throws SQLException { 50 | 51 | } 52 | 53 | @Override 54 | public long cleanupExpiredGlobalLogs(LocalDateTime effectiveDeadlineTime) throws SQLException { 55 | return 0L; 56 | } 57 | 58 | @Override 59 | public long cleanupExpiredRequestLogs(LocalDateTime effectiveDeadlineTime) throws SQLException { 60 | return 0L; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/axios.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 {redirectOn401} from './axios'; 18 | 19 | describe('redirectOn401', () => { 20 | it('should not redirect on 500', async () => { 21 | window.location.assign = jest.fn(); 22 | 23 | const error = { 24 | response: { 25 | status: 500 26 | } 27 | }; 28 | 29 | try { 30 | await redirectOn401()(error); 31 | } catch (e) { 32 | expect(e).toBe(error); 33 | } 34 | 35 | expect(window.location.assign).not.toBeCalled(); 36 | }); 37 | 38 | it('should redirect on 401', async () => { 39 | window.location.assign = jest.fn(); 40 | 41 | const error = { 42 | response: { 43 | status: 401 44 | } 45 | }; 46 | 47 | try { 48 | await redirectOn401()(error); 49 | } catch (e) { 50 | expect(e).toBe(error); 51 | } 52 | 53 | expect(window.location.assign).toBeCalledWith('login?redirectTo=http%3A%2F%2Fexample.com%2F'); 54 | }); 55 | 56 | it('should not redirect on 401 for predicate yields false', async () => { 57 | window.location.assign = jest.fn(); 58 | 59 | const error = { 60 | response: { 61 | status: 401 62 | } 63 | }; 64 | 65 | try { 66 | await redirectOn401(() => false)(error); 67 | } catch (e) { 68 | expect(e).toBe(error); 69 | } 70 | 71 | expect(window.location.assign).not.toBeCalled(); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/cache/LoggingCache.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.cache; 19 | 20 | import org.minbox.framework.logging.client.MinBoxLoggingException; 21 | import org.minbox.framework.logging.core.MinBoxLog; 22 | 23 | import java.util.List; 24 | 25 | /** 26 | * ApiBoot Logging Cache 27 | * 28 | * @author 恒宇少年 29 | */ 30 | public interface LoggingCache { 31 | /** 32 | * Cache Single MinBoxLog 33 | * 34 | * @param log MinBoxLog 35 | * @throws MinBoxLoggingException Logging Exception 36 | */ 37 | void cache(MinBoxLog log) throws MinBoxLoggingException; 38 | 39 | /** 40 | * Get Any One MinBoxLog 41 | * 42 | * @return MinBoxLog 43 | * @throws MinBoxLoggingException Logging Exception 44 | */ 45 | MinBoxLog getAnyOne() throws MinBoxLoggingException; 46 | 47 | /** 48 | * Gets the specified number of MinBoxLog 49 | * 50 | * @param count get count number 51 | * @return MinBoxLog Collection 52 | * @throws MinBoxLoggingException Logging Exception 53 | */ 54 | List getLogs(int count) throws MinBoxLoggingException; 55 | 56 | /** 57 | * Gets All Of MinBoxLog 58 | * 59 | * @return MinBoxLog Collection 60 | * @throws MinBoxLoggingException Logging Exception 61 | */ 62 | List getAll() throws MinBoxLoggingException; 63 | } 64 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/LogThreadLocal.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client; 19 | 20 | import com.alibaba.ttl.TransmittableThreadLocal; 21 | import org.minbox.framework.logging.core.MinBoxLog; 22 | 23 | /** 24 | * Using threadLocal to store log objects in multithreaded situations 25 | * 26 | * @author 恒宇少年 27 | */ 28 | public class LogThreadLocal { 29 | /** 30 | * The Request Logs 31 | * Solve the problem of the {@link MinBoxLog} object of the child parent thread 32 | * https://gitee.com/minbox-projects/minbox-logging/issues/I11QKJ 33 | * 34 | * @see TransmittableThreadLocal 35 | * @see MinBoxLog 36 | */ 37 | private static final TransmittableThreadLocal LOGS = new TransmittableThreadLocal<>(); 38 | 39 | /** 40 | * Get This Thread ApiBoot Log Object Instance 41 | * 42 | * @return This Thread ApiBoot Log 43 | */ 44 | public static MinBoxLog get() { 45 | return LOGS.get(); 46 | } 47 | 48 | /** 49 | * Set This Thread ApiBoot Log Object Instance 50 | * 51 | * @param minBoxLog This Thread ApiBoot Log 52 | */ 53 | public static void set(MinBoxLog minBoxLog) { 54 | LOGS.set(minBoxLog); 55 | } 56 | 57 | /** 58 | * Remove This Thread ApiBoot Log Object Instance 59 | */ 60 | public static void remove() { 61 | LOGS.remove(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-status.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 {mount} from '@vue/test-utils'; 18 | import moment from 'moment'; 19 | import sbaStatus from './sba-status'; 20 | 21 | moment.now = () => +new Date(1318781879406); 22 | 23 | describe('application-status', () => { 24 | 25 | const testSnapshotForStatus = (status, date) => { 26 | const wrapper = mount(sbaStatus, { 27 | propsData: { 28 | status, 29 | date 30 | }, 31 | stubs: { 32 | 'font-awesome-icon': true 33 | } 34 | }); 35 | expect(wrapper.vm.$el).toMatchSnapshot(); 36 | }; 37 | 38 | it('should match the snapshot with status UP with Timestamp', () => { 39 | testSnapshotForStatus('UP', 1318781000000); 40 | }); 41 | 42 | it('should match the snapshot with status RESTRICTED', () => { 43 | testSnapshotForStatus('RESTRICTED'); 44 | }); 45 | 46 | it('should match the snapshot with status OUT_OF_SERVICE', () => { 47 | testSnapshotForStatus('OUT_OF_SERVICE'); 48 | }); 49 | 50 | it('should match the snapshot with status DOWN', () => { 51 | testSnapshotForStatus('DOWN'); 52 | }); 53 | 54 | it('should match the snapshot with status UNKNOWN', () => { 55 | testSnapshotForStatus('UNKNOWN'); 56 | }); 57 | 58 | it('should match the snapshot with status OFFLINE', () => { 59 | testSnapshotForStatus('OFFLINE'); 60 | }); 61 | 62 | it('should match the snapshot with custom status', () => { 63 | testSnapshotForStatus('?'); 64 | }); 65 | 66 | }); 67 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/discovery/lb/support/RandomWeightedStrategy.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.admin.discovery.lb.support; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | import org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceNode; 5 | import org.springframework.util.ObjectUtils; 6 | 7 | import java.util.List; 8 | import java.util.SortedMap; 9 | import java.util.TreeMap; 10 | 11 | /** 12 | * The {@link org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceStrategy} random strategy 13 | * 14 | * @author 恒宇少年 15 | * @see DefaultLoadBalanceStrategy 16 | * @see org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceStrategy 17 | */ 18 | public class RandomWeightedStrategy extends DefaultLoadBalanceStrategy { 19 | /** 20 | * logging admin node list 21 | * {@link LoadBalanceNode} 22 | */ 23 | private TreeMap nodes = new TreeMap(); 24 | 25 | /** 26 | * lookup logging admin load-balanced address {@link LoadBalanceNode#getAddress()} 27 | * Lookup according to random weight admin address 28 | * get firstKey by {@link SortedMap#tailMap(Object)} 29 | * 30 | * @param adminAddress logging admin address array 31 | * @return Load-balanced addresses 32 | * @throws MinBoxLoggingException MinBox Logging Exception 33 | */ 34 | @Override 35 | public String lookup(String[] adminAddress) throws MinBoxLoggingException { 36 | List loadBalanceNodes = initNodeList(adminAddress); 37 | loadBalanceNodes.stream().forEach(node -> { 38 | double lastWeight = this.nodes.size() == 0 ? 0 : this.nodes.lastKey().doubleValue(); 39 | this.nodes.put(node.getInitWeight() + lastWeight, node); 40 | }); 41 | Double randomWeight = this.nodes.lastKey() * Math.random(); 42 | SortedMap tailMap = this.nodes.tailMap(randomWeight, false); 43 | if (ObjectUtils.isEmpty(tailMap)) { 44 | throw new MinBoxLoggingException("No load balancing node was found"); 45 | } 46 | return this.nodes.get(tailMap.firstKey()).getAddress(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/http/openfeign/LoggingOpenFeignInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.http.openfeign; 19 | 20 | import feign.RequestInterceptor; 21 | import feign.RequestTemplate; 22 | import org.minbox.framework.logging.client.LoggingConstant; 23 | import org.minbox.framework.logging.client.LogThreadLocal; 24 | import org.minbox.framework.logging.core.MinBoxLog; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | import org.springframework.util.ObjectUtils; 28 | 29 | /** 30 | * Openfeign Request Interceptor 31 | * Requests initiated by openfeign carry ApiBoot TraceId and spanId 32 | * 33 | * @author 恒宇少年 34 | */ 35 | public class LoggingOpenFeignInterceptor implements RequestInterceptor { 36 | /** 37 | * logger instance 38 | */ 39 | static Logger logger = LoggerFactory.getLogger(LoggingOpenFeignInterceptor.class); 40 | 41 | @Override 42 | public void apply(RequestTemplate requestTemplate) { 43 | MinBoxLog log = LogThreadLocal.get(); 44 | if (!ObjectUtils.isEmpty(log)) { 45 | requestTemplate.header(LoggingConstant.HEADER_NAME_TRACE_ID, log.getTraceId()); 46 | requestTemplate.header(LoggingConstant.HEADER_NAME_PARENT_SPAN_ID, log.getSpanId()); 47 | logger.debug("RequestUri:{}, Method:{},Setting Logging TraceId:{},SpanId:{} With Openfeign.", 48 | requestTemplate.url(), requestTemplate.request().httpMethod().toString(), log.getTraceId(), log.getSpanId()); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/viewRegistry.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 {VIEW_GROUP} from './views'; 18 | 19 | const createTextVNode = (label) => { 20 | return { 21 | render() { 22 | return this._v(this.$t(label)) 23 | } 24 | } 25 | }; 26 | 27 | export default class ViewRegistry { 28 | constructor() { 29 | this._views = []; 30 | this._redirects = []; 31 | } 32 | 33 | get views() { 34 | return this._views; 35 | } 36 | 37 | get routes() { 38 | return [ 39 | ...this._toRoutes(this._views, v => v.path && !v.parent), 40 | ...this._redirects 41 | ] 42 | } 43 | 44 | addView(...views) { 45 | views.forEach(view => this._addView(view)); 46 | } 47 | 48 | addRedirect(path, redirect) { 49 | if (typeof redirect === 'string') { 50 | this._redirects.push({path, redirect: {name: redirect}}); 51 | } else { 52 | this._redirects.push({path, redirect}); 53 | } 54 | } 55 | 56 | _addView(view) { 57 | if (view.label && !view.handle) { 58 | view.handle = createTextVNode(view.label); 59 | } 60 | if (!view.group) { 61 | view.group = VIEW_GROUP.NONE; 62 | } 63 | 64 | this._views.push(view); 65 | } 66 | 67 | _toRoutes(views, filter) { 68 | return views.filter(filter).map( 69 | p => { 70 | const children = this._toRoutes(views, v => v.parent === p.name); 71 | return ({ 72 | path: p.path, 73 | name: children.length === 0 ? p.name : undefined, 74 | component: p.component, 75 | props: p.props, 76 | meta: {view: p}, 77 | children 78 | }); 79 | } 80 | ) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /minbox-logging-samples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging 7 | org.minbox.framework 8 | ${revision} 9 | 10 | 4.0.0 11 | pom 12 | 13 | true 14 | true 15 | true 16 | 2.6.6 17 | 2.3.7 18 | 19 | 20 | Logging Client、Logging Admin使用示例 21 | 22 | 23 | logging-client-sample 24 | logging-admin-sample 25 | 26 | minbox-logging-samples 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-dependencies 33 | ${spring-boot.version} 34 | pom 35 | import 36 | 37 | 38 | 39 | org.minbox.framework 40 | minbox-logging-dependencies 41 | ${project.version} 42 | import 43 | pom 44 | 45 | 46 | 47 | org.minbox.framework 48 | api-boot-dependencies 49 | ${api-boot.version} 50 | pom 51 | import 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/interceptor/webflux/LoggingWebFluxInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.interceptor.webflux; 2 | 3 | import org.minbox.framework.logging.client.LoggingFactoryBean; 4 | import org.minbox.framework.logging.client.interceptor.LoggingAbstractInterceptor; 5 | import org.minbox.framework.util.UrlUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.http.server.reactive.ServerHttpRequest; 9 | import org.springframework.web.server.ServerWebExchange; 10 | import org.springframework.web.server.WebFilter; 11 | import org.springframework.web.server.WebFilterChain; 12 | import reactor.core.publisher.Mono; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * {@link org.springframework.web.server.WebFilter} 18 | * 19 | * @author 恒宇少年 20 | */ 21 | public class LoggingWebFluxInterceptor extends LoggingAbstractInterceptor implements WebFilter { 22 | /** 23 | * logger instance 24 | */ 25 | static Logger logger = LoggerFactory.getLogger(LoggingWebFluxInterceptor.class); 26 | /** 27 | * {@link LoggingFactoryBean} 28 | */ 29 | private LoggingFactoryBean factoryBean; 30 | 31 | public LoggingWebFluxInterceptor(LoggingFactoryBean factoryBean) { 32 | super(factoryBean); 33 | this.factoryBean = factoryBean; 34 | } 35 | 36 | /** 37 | * Intercept requests and generate logs 38 | * 39 | * @param exchange {@link ServerWebExchange} 40 | * @param chain {@link WebFilterChain} 41 | * @return {@link Mono} 42 | */ 43 | @Override 44 | public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { 45 | ServerHttpRequest request = exchange.getRequest(); 46 | boolean isIgnore = checkUriIsIgnore(request); 47 | if (isIgnore) { 48 | return chain.filter(exchange); 49 | } 50 | return chain.filter(exchange); 51 | } 52 | 53 | /** 54 | * check request uri is ignore {@link UrlUtils#isIgnore(List, String)} 55 | * 56 | * @param request {@link ServerHttpRequest} 57 | * @return uri is ignore 58 | */ 59 | private boolean checkUriIsIgnore(ServerHttpRequest request) { 60 | String uri = request.getURI().getPath(); 61 | return UrlUtils.isIgnore(factoryBean.getIgnorePaths(), uri); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/__snapshots__/sba-status.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`application-status should match the snapshot with custom status 1`] = ` 4 |

7 | 10 | 11 | 12 |
13 | `; 14 | 15 | exports[`application-status should match the snapshot with status DOWN 1`] = ` 16 |
19 | 23 | 24 | 25 |
26 | `; 27 | 28 | exports[`application-status should match the snapshot with status OFFLINE 1`] = ` 29 |
32 | 36 | 37 | 38 |
39 | `; 40 | 41 | exports[`application-status should match the snapshot with status OUT_OF_SERVICE 1`] = ` 42 |
45 | 49 | 50 | 51 |
52 | `; 53 | 54 | exports[`application-status should match the snapshot with status RESTRICTED 1`] = ` 55 |
58 | 62 | 63 | 64 |
65 | `; 66 | 67 | exports[`application-status should match the snapshot with status UNKNOWN 1`] = ` 68 |
71 | 75 | 76 | 77 |
78 | `; 79 | 80 | exports[`application-status should match the snapshot with status UP with Timestamp 1`] = ` 81 |
84 | 88 | 89 | 90 | 14m 91 | 92 |
93 | `; 94 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/mapping/LoggingRequestMappingHandlerMapping.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.core.mapping; 19 | 20 | import org.minbox.framework.logging.core.annotation.Endpoint; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | import org.springframework.core.annotation.AnnotationUtils; 24 | import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; 25 | 26 | import javax.annotation.PostConstruct; 27 | 28 | 29 | /** 30 | * ApiBoot Logging RequestMapping Handler 31 | * 32 | * @author 恒宇少年 33 | */ 34 | 35 | public class LoggingRequestMappingHandlerMapping extends RequestMappingHandlerMapping { 36 | /** 37 | * The bean name of {@link LoggingRequestMappingHandlerMapping} 38 | */ 39 | public static final String BEAN_NAME = "loggingRequestMappingHandlerMapping"; 40 | /** 41 | * logger instance 42 | */ 43 | static Logger logger = LoggerFactory.getLogger(LoggingRequestMappingHandlerMapping.class); 44 | 45 | @PostConstruct 46 | public void setOrder() { 47 | super.setOrder(0); 48 | } 49 | 50 | /** 51 | * Only Endpoint Class with @Endpoint annotation is processed 52 | * 53 | * @param beanType endpoint bean type class 54 | * @return is handler 55 | */ 56 | @Override 57 | protected boolean isHandler(Class beanType) { 58 | boolean isEndpoint = AnnotationUtils.findAnnotation(beanType, Endpoint.class) != null; 59 | if (isEndpoint) { 60 | logger.info("Load ApiBoot Logging Endpoint,BeanType:[{}]", beanType.getName()); 61 | } 62 | return isEndpoint; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /minbox-logging-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | minbox-logging-dependencies 7 | org.minbox.framework 8 | ${revision} 9 | ../minbox-logging-dependencies 10 | 11 | 4.0.0 12 | jar 13 | minbox-logging-client 14 | 15 | 2.11.5 16 | 3.1.1 17 | 18 | 19 | 20 | org.minbox.framework 21 | minbox-logging-core 22 | ${project.version} 23 | 24 | 25 | javax.servlet 26 | javax.servlet-api 27 | true 28 | 29 | 30 | org.springframework 31 | spring-webmvc 32 | true 33 | 34 | 35 | org.springframework 36 | spring-webflux 37 | true 38 | 39 | 40 | org.springframework.cloud 41 | spring-cloud-starter-openfeign 42 | ${openfeign.version} 43 | true 44 | 45 | 46 | org.minbox.framework 47 | minbox-sequence 48 | 49 | 50 | com.alibaba 51 | transmittable-thread-local 52 | ${transmittable-thread-local.version} 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-status.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 27 | 28 | 60 | 61 | 94 | -------------------------------------------------------------------------------- /minbox-logging-core/src/main/java/org/minbox/framework/logging/core/LoggingClientNotice.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.core; 19 | 20 | import lombok.Data; 21 | 22 | import java.io.Serializable; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * ApiBoot Logging Client Notice Object 28 | * 29 | * @author 恒宇少年 30 | */ 31 | @Data 32 | public class LoggingClientNotice implements Serializable { 33 | /** 34 | * Client Service Id 35 | */ 36 | private String clientServiceId; 37 | /** 38 | * Client Service Ip Address 39 | */ 40 | private String clientServiceIp; 41 | /** 42 | * Client Service Port 43 | */ 44 | private Integer clientServicePort; 45 | /** 46 | * Report Time Millis 47 | */ 48 | private Long reportTimeMillis = System.currentTimeMillis(); 49 | /** 50 | * ApiBoot Logging Request Log 51 | */ 52 | private List loggers = new ArrayList<>(); 53 | 54 | /** 55 | * Create new {@link LoggingClientNotice} instance 56 | * 57 | * @param clientServiceId {@link #clientServiceId} 58 | * @param clientServiceIp {@link #clientServiceIp} 59 | * @param clientServicePort {@link #clientServicePort} 60 | * @param loggers {@link #loggers} 61 | * @return {@link LoggingClientNotice} 62 | */ 63 | public static LoggingClientNotice instance( 64 | String clientServiceId, String clientServiceIp, Integer clientServicePort, List loggers) { 65 | LoggingClientNotice notice = new LoggingClientNotice(); 66 | notice.setClientServiceId(clientServiceId); 67 | notice.setClientServiceIp(clientServiceIp); 68 | notice.setClientServicePort(clientServicePort); 69 | notice.setLoggers(loggers); 70 | return notice; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/autolink.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 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 | * http://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 autolink, {Autolink} from './autolink' 18 | 19 | describe('autolink should', () => { 20 | it('return the input string for normal text', () => { 21 | const str = 'This is just a normal text containing no hyperlinks'; 22 | expect(autolink(str)).toBe(str); 23 | }); 24 | 25 | it('return string with anchor tag for the hyperlink', () => { 26 | const str = 'Please visit http://example.com.'; 27 | expect(autolink(str)).toBe('Please visit http://example.com.'); 28 | }); 29 | 30 | it('return string with anchor tag with shortened text for the hyperlink', () => { 31 | const str = 'Please visit http://extraordinary.com/very/very/log/hyperlink.'; 32 | 33 | const customAutolink = new Autolink({ 34 | truncate: { 35 | length: 30, 36 | location: 'smart' 37 | }, 38 | }); 39 | expect(customAutolink(str)).toBe('Please visit extraordinary.com/very…rlink.'); 40 | }); 41 | 42 | it('return string with anchor for hyperlinks in dense json', () => { 43 | const str = '{"name":"John Smith","links":[{"rel":"random-link1","href":"https://localhost:8000/api/123/query?action=do_something&age=21","hreflang":null,"media":null,"title":null,"type":null,"deprecation":null}]}'; 44 | expect(autolink(str)).toBe('{"name":"John Smith","links":[{"rel":"random-link1","href":"https://localhost:8000/api/123/query?action=do_something&age=21","hreflang":null,"media":null,"title":null,"type":null,"deprecation":null}]}'); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/components/sba-panel.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 40 | 41 | 69 | 70 | 91 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/logtail.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 {concatMap, EMPTY, of, timer} from '@/utils/rxjs'; 18 | 19 | export default (getFn, interval, initialSize = 300 * 1024) => { 20 | let range = `bytes=-${initialSize}`; 21 | let size = 0; 22 | 23 | return timer(0, interval) 24 | .pipe( 25 | concatMap(() => getFn({headers: {range, 'Accept': 'text/plain'}})), 26 | concatMap(response => { 27 | const initial = size === 0; 28 | const contentLength = response.data.length; 29 | if (response.status === 200) { 30 | if (!initial) { 31 | throw 'Expected 206 - Partial Content on subsequent requests.'; 32 | } 33 | size = contentLength; 34 | } else if (response.status === 206) { 35 | size = parseInt(response.headers['content-range'].split('/')[1]); 36 | } else { 37 | throw 'Unexpected response status: ' + response.status; 38 | } 39 | 40 | // Reload the last byte to avoid a 416: Range unsatisfiable. 41 | // If the response has length = 1 the file hasn't beent changed. 42 | // If the response status is 416 the logfile has been truncated. 43 | range = `bytes=${size - 1}-`; 44 | 45 | let addendum = null; 46 | let skipped = 0; 47 | 48 | if (initial) { 49 | if (contentLength >= size) { 50 | addendum = response.data; 51 | } else { 52 | // In case of a partial response find the first line break. 53 | addendum = response.data.substring(response.data.indexOf('\n') + 1); 54 | skipped = size - addendum.length; 55 | } 56 | } else if (response.data.length > 1) { 57 | // Remove the first byte which has been part of the previos response. 58 | addendum = response.data.substring(1); 59 | } 60 | 61 | return addendum ? of({ 62 | totalBytes: size, 63 | skipped, 64 | addendum 65 | }) : EMPTY; 66 | }) 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/rxjs.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 {defer} from 'rxjs/internal/observable/defer'; 18 | import {tap} from 'rxjs/internal/operators/tap'; 19 | 20 | export {throwError} from 'rxjs/internal/observable/throwError'; 21 | export {of} from 'rxjs/internal/observable/of'; 22 | export {defer} from 'rxjs/internal/observable/defer'; 23 | export {concat} from 'rxjs/internal/observable/concat'; 24 | export {EMPTY} from 'rxjs/internal/observable/empty'; 25 | export {from} from 'rxjs/internal/observable/from'; 26 | export {timer} from 'rxjs/internal/observable/timer'; 27 | export {Observable} from 'rxjs/internal/Observable'; 28 | export {Subject} from 'rxjs/internal/Subject'; 29 | export {animationFrame as animationFrameScheduler} from 'rxjs/internal/scheduler/animationFrame'; 30 | export {concatMap} from 'rxjs/internal/operators/concatMap'; 31 | export {delay} from 'rxjs/internal/operators/delay'; 32 | export {debounceTime} from 'rxjs/internal/operators/debounceTime'; 33 | export {merge} from 'rxjs/internal/operators/merge'; 34 | export {map} from 'rxjs/internal/operators/map'; 35 | export {retryWhen} from 'rxjs/internal/operators/retryWhen'; 36 | export {tap} from 'rxjs/internal/operators/tap'; 37 | export {filter} from 'rxjs/internal/operators/filter'; 38 | export {concatAll} from 'rxjs/internal/operators/concatAll'; 39 | export {ignoreElements} from 'rxjs/internal/operators/ignoreElements'; 40 | export {bufferTime} from 'rxjs/internal/operators/bufferTime'; 41 | export {finalize} from 'rxjs/internal/operators/finalize'; 42 | 43 | export const doOnSubscribe = cb => source => 44 | defer(() => { 45 | cb(); 46 | return source 47 | }); 48 | 49 | export const listen = (cb, execDelay = 150) => source => { 50 | let handle = null; 51 | return source.pipe( 52 | doOnSubscribe(() => handle = setTimeout(() => cb('executing'), execDelay)), 53 | tap({ 54 | complete: () => { 55 | handle && clearTimeout(handle); 56 | cb('completed'); 57 | }, 58 | error: (error) => { 59 | console.warn('Operation failed:', error); 60 | handle && clearTimeout(handle); 61 | cb('failed'); 62 | } 63 | }) 64 | ) 65 | }; 66 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/notice/support/LoggingAdminNotice.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.notice.support; 2 | 3 | import org.minbox.framework.logging.client.LoggingFactoryBean; 4 | import org.minbox.framework.logging.client.admin.report.LoggingAdminReport; 5 | import org.minbox.framework.logging.client.cache.LoggingCache; 6 | import org.minbox.framework.logging.client.notice.LoggingNotice; 7 | import org.minbox.framework.logging.core.MinBoxLog; 8 | import org.minbox.framework.logging.core.ReportAway; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.lang.Nullable; 12 | 13 | import java.util.Arrays; 14 | 15 | /** 16 | * Logging admin notification 17 | * 18 | * @author 恒宇少年 19 | */ 20 | public class LoggingAdminNotice implements LoggingNotice { 21 | /** 22 | * the bean name of {@link LoggingAdminNotice} 23 | */ 24 | public static final String BEAN_NAME = "loggingAdminNotice"; 25 | /** 26 | * logger instance 27 | */ 28 | static Logger logger = LoggerFactory.getLogger(LoggingAdminNotice.class); 29 | 30 | /** 31 | * logging factory bean 32 | * {@link LoggingFactoryBean} 33 | * {@link LoggingCache} 34 | * {@link LoggingAdminReport} 35 | */ 36 | @Nullable 37 | private LoggingFactoryBean factoryBean; 38 | 39 | /** 40 | * Injecting {@link LoggingFactoryBean} through constructor injection 41 | * 42 | * @param factoryBean {@link LoggingFactoryBean} 43 | */ 44 | public LoggingAdminNotice(@Nullable LoggingFactoryBean factoryBean) { 45 | this.factoryBean = factoryBean; 46 | } 47 | 48 | /** 49 | * if just report away,execute report logs to admin 50 | * if timing report away,cache logs to {@link LoggingCache} support, 51 | * wait for {@link org.minbox.framework.logging.client.admin.report.LoggingReportScheduled} execute report 52 | * 53 | * @param minBoxLog ApiBoot Log 54 | */ 55 | @Override 56 | public void notice(MinBoxLog minBoxLog) { 57 | ReportAway reportAway = factoryBean.getReportAway(); 58 | switch (reportAway) { 59 | case just: 60 | LoggingAdminReport loggingAdminReport = factoryBean.getLoggingAdminReport(); 61 | loggingAdminReport.report(Arrays.asList(minBoxLog)); 62 | break; 63 | case timing: 64 | factoryBean.getLoggingCache().cache(minBoxLog); 65 | logger.debug("Cache Request Logging Complete."); 66 | break; 67 | default: 68 | logger.warn("Unsupported reporting away."); 69 | break; 70 | } 71 | } 72 | 73 | @Override 74 | public int getOrder() { 75 | return HIGHEST_PRECEDENCE + 1; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/http/rest/LoggingRestTemplateInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.http.rest; 19 | 20 | import org.minbox.framework.logging.client.LoggingConstant; 21 | import org.minbox.framework.logging.client.LogThreadLocal; 22 | import org.minbox.framework.logging.core.MinBoxLog; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import org.springframework.http.HttpRequest; 26 | import org.springframework.http.client.ClientHttpRequestExecution; 27 | import org.springframework.http.client.ClientHttpRequestInterceptor; 28 | import org.springframework.http.client.ClientHttpResponse; 29 | import org.springframework.util.ObjectUtils; 30 | 31 | import java.io.IOException; 32 | 33 | 34 | /** 35 | * ApiBoot Logging RestTemplate Interceptor 36 | * Pass-through traceId and spanId 37 | * 38 | * @author 恒宇少年 39 | */ 40 | public class LoggingRestTemplateInterceptor implements ClientHttpRequestInterceptor { 41 | /** 42 | * logger instance 43 | */ 44 | static Logger logger = LoggerFactory.getLogger(LoggingRestTemplateInterceptor.class); 45 | 46 | /** 47 | * Request Exception 48 | * 49 | * @param request {@link HttpRequest} 50 | * @param body Request Body 51 | * @param execution Execute 52 | * @return {@link ClientHttpResponse} 53 | * @throws IOException 54 | */ 55 | @Override 56 | public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { 57 | MinBoxLog log = LogThreadLocal.get(); 58 | if (!ObjectUtils.isEmpty(log)) { 59 | request.getHeaders().add(LoggingConstant.HEADER_NAME_TRACE_ID, log.getTraceId()); 60 | request.getHeaders().add(LoggingConstant.HEADER_NAME_PARENT_SPAN_ID, log.getSpanId()); 61 | logger.debug("RequestUri:{}, Method:{},Setting Logging TraceId:{},SpanId:{} With RestTemplate.", 62 | request.getURI().getPath(), request.getMethod().toString(), log.getTraceId(), log.getSpanId()); 63 | } 64 | return execution.execute(request, body); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/services/application.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 {convertBody, hasMatchingContentType, throwOnError} from './application'; 18 | 19 | describe('hasMatchingContentType', () => { 20 | it('should match content-type', () => { 21 | const matches = hasMatchingContentType( 22 | 'application/json;charset=UTF-8', 23 | ['application/vnd.spring-boot.actuator.v1+json', 'application/json'] 24 | ); 25 | expect(matches).toBe(true); 26 | }); 27 | 28 | it('should not match content-types', () => { 29 | const matches = hasMatchingContentType( 30 | 'application/html;charset=UTF-8', 31 | ['application/vnd.spring-boot.actuator.v1+json', 'application/json'] 32 | ); 33 | expect(matches).toBe(false); 34 | }); 35 | 36 | it('should not match undefined', () => { 37 | const matches = hasMatchingContentType( 38 | undefined, 39 | ['application/vnd.spring-boot.actuator.v1+json', 'application/json'] 40 | ); 41 | expect(matches).toBe(false); 42 | }); 43 | }); 44 | 45 | describe('throwOnError', () => { 46 | it('should not throw on no response', () => { 47 | throwOnError([]) 48 | }); 49 | 50 | it('should not throw on no error', () => { 51 | throwOnError([{status: 200}, {status: 100}, {status: 302}]) 52 | }); 53 | 54 | it('should not throw on error', () => { 55 | expect(() => throwOnError([{status: 200}, {status: 400}, {status: 302}])).toThrow() 56 | }); 57 | }); 58 | 59 | describe('convertBody', () => { 60 | it('should not convert empty responses', () => { 61 | expect(convertBody([])).toEqual([]) 62 | }); 63 | 64 | it('should not convert empty body', () => { 65 | expect(convertBody([{}])).toEqual([{}]) 66 | }); 67 | 68 | it('should not convert non-json body', () => { 69 | expect(convertBody([ 70 | {body: 'foobar', contentType: 'text/plain'} 71 | ])).toEqual([ 72 | {body: 'foobar', contentType: 'text/plain'} 73 | ]) 74 | }); 75 | 76 | it('should convert json body', () => { 77 | expect(convertBody([ 78 | {body: '{"foo": "bar"}', contentType: 'application/json'} 79 | ])).toEqual([ 80 | {body: {'foo': 'bar'}, contentType: 'application/json'} 81 | ]) 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/rxjs.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 {concat, EMPTY, of, throwError} from '@/utils/rxjs'; 18 | import {delay, doOnSubscribe, listen} from './rxjs'; 19 | 20 | describe('doOnSubscribe', () => { 21 | it('should call callback when subscribing', done => { 22 | const cb = jest.fn(); 23 | EMPTY.pipe( 24 | doOnSubscribe(cb) 25 | ).subscribe({ 26 | complete: () => { 27 | expect(cb).toHaveBeenCalledTimes(1); 28 | done(); 29 | } 30 | }); 31 | }); 32 | }); 33 | 34 | describe('listen', () => { 35 | it('should call callback with complete', done => { 36 | const cb = jest.fn(); 37 | EMPTY.pipe( 38 | listen(cb) 39 | ).subscribe({ 40 | complete: () => { 41 | expect(cb).toHaveBeenCalledTimes(1); 42 | expect(cb).toHaveBeenCalledWith('completed'); 43 | done(); 44 | } 45 | }); 46 | }); 47 | 48 | it('should call callback with executing and complete', done => { 49 | const cb = jest.fn(); 50 | of(1).pipe( 51 | delay(10), 52 | listen(cb, 1) 53 | ).subscribe({ 54 | complete: () => { 55 | expect(cb).toHaveBeenCalledTimes(2); 56 | expect(cb).toHaveBeenCalledWith('executing'); 57 | expect(cb).toHaveBeenCalledWith('completed'); 58 | done(); 59 | } 60 | }); 61 | }); 62 | 63 | it('should call callback with failed', done => { 64 | const cb = jest.fn(); 65 | throwError(new Error('test')).pipe( 66 | listen(cb) 67 | ).subscribe({ 68 | error: () => { 69 | expect(cb).toHaveBeenCalledTimes(1); 70 | expect(cb).toHaveBeenCalledWith('failed'); 71 | done(); 72 | } 73 | }); 74 | }); 75 | 76 | it('should call callback with executing and failed', done => { 77 | const cb = jest.fn(); 78 | 79 | concat( 80 | of(1).pipe(delay(10)), 81 | throwError(new Error('test')) 82 | ).pipe( 83 | listen(cb, 1) 84 | ).subscribe({ 85 | error: () => { 86 | expect(cb).toHaveBeenCalledTimes(2); 87 | expect(cb).toHaveBeenCalledWith('executing'); 88 | expect(cb).toHaveBeenCalledWith('failed'); 89 | done(); 90 | } 91 | }); 92 | }); 93 | 94 | }); 95 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/services/notification-filter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 sbaConfig from '@/sba-config' 18 | import axios from '@/utils/axios'; 19 | import uri from '@/utils/uri'; 20 | import moment from 'moment'; 21 | 22 | class NotificationFilter { 23 | constructor({expiry, ...filter}) { 24 | Object.assign(this, filter); 25 | this.expiry = expiry ? moment(expiry) : null; 26 | } 27 | 28 | affects(obj) { 29 | if (!obj) { 30 | return false; 31 | } 32 | 33 | if (this.isApplicationFilter) { 34 | return this.applicationName === obj.name; 35 | } 36 | 37 | if (this.isInstanceFilter) { 38 | return this.instanceId === obj.id; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | get isApplicationFilter() { 45 | return this.hasOwnProperty('applicationName'); 46 | } 47 | 48 | get isInstanceFilter() { 49 | return this.hasOwnProperty('instanceId'); 50 | } 51 | 52 | async delete() { 53 | return axios.delete(uri`notifications/filters/${this.id}`); 54 | } 55 | 56 | static isSupported() { 57 | return Boolean(sbaConfig.uiSettings.notificationFilterEnabled); 58 | } 59 | 60 | static async getFilters() { 61 | return axios.get('notifications/filters', { 62 | transformResponse: NotificationFilter._transformResponse 63 | }); 64 | } 65 | 66 | static async addFilter(object, ttl) { 67 | const params = {ttl}; 68 | if (object.hasOwnProperty('name')) { 69 | params.applicationName = object.name; 70 | } else if (object.hasOwnProperty('id')) { 71 | params.instanceId = object.id; 72 | } 73 | return axios.post('notifications/filters', null, { 74 | params, 75 | transformResponse: NotificationFilter._transformResponse 76 | }); 77 | } 78 | 79 | static _transformResponse(data) { 80 | if (!data) { 81 | return data; 82 | } 83 | const json = JSON.parse(data); 84 | if (json instanceof Array) { 85 | return json.map(NotificationFilter._toNotificationFilters).filter(f => !f.expired); 86 | } 87 | return NotificationFilter._toNotificationFilters(json); 88 | } 89 | 90 | static _toNotificationFilters(notificationFilter) { 91 | return new NotificationFilter(notificationFilter); 92 | } 93 | 94 | } 95 | 96 | export default NotificationFilter; 97 | 98 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/utils/collections.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 | 18 | import {anyValueMatches} from './collections'; 19 | 20 | describe('anyValueMatches', () => { 21 | it('should return predicate value', () => { 22 | const predicate = jest.fn(() => true); 23 | expect(anyValueMatches('test', predicate)).toBe(true); 24 | }); 25 | 26 | it('should call predicate for string', () => { 27 | const predicate = jest.fn(); 28 | anyValueMatches('test', predicate); 29 | expect(predicate).toHaveBeenCalledWith('test'); 30 | }); 31 | 32 | it('should call predicate for number', () => { 33 | const predicate = jest.fn(); 34 | anyValueMatches(1, predicate); 35 | expect(predicate).toHaveBeenCalledWith(1); 36 | }); 37 | 38 | it('should call predicate for boolean', () => { 39 | const predicate = jest.fn(); 40 | anyValueMatches(true, predicate); 41 | expect(predicate).toHaveBeenCalledWith(true); 42 | }); 43 | 44 | it('should call predicate for null', () => { 45 | const predicate = jest.fn(); 46 | anyValueMatches(null, predicate); 47 | expect(predicate).toHaveBeenCalledWith(null); 48 | }); 49 | 50 | it('should call predicate for undefined', () => { 51 | const predicate = jest.fn(); 52 | anyValueMatches(undefined, predicate); 53 | expect(predicate).toHaveBeenCalledWith(undefined); 54 | }); 55 | 56 | it('should not call predicate for empty object', () => { 57 | const predicate = jest.fn(); 58 | anyValueMatches({}, predicate); 59 | expect(predicate).not.toHaveBeenCalled() 60 | }); 61 | 62 | it('should not call predicate for empty array', () => { 63 | const predicate = jest.fn(); 64 | anyValueMatches([], predicate); 65 | expect(predicate).not.toHaveBeenCalled() 66 | }); 67 | 68 | it('should not call predicate for elements in array', () => { 69 | const predicate = jest.fn(); 70 | anyValueMatches(['test', 1, true, {value: 'nested-obj'}, ['nested-array'], [], {}], predicate); 71 | expect(predicate).toHaveBeenNthCalledWith(1, 'test'); 72 | expect(predicate).toHaveBeenNthCalledWith(2, 1); 73 | expect(predicate).toHaveBeenNthCalledWith(3, true); 74 | expect(predicate).toHaveBeenNthCalledWith(4, 'nested-obj'); 75 | expect(predicate).toHaveBeenNthCalledWith(5, 'nested-array'); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/global/support/GlobalLoggingMemoryStorage.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.global.support; 2 | 3 | import org.minbox.framework.logging.client.global.AbstractGlobalLogging; 4 | import org.minbox.framework.logging.client.global.GlobalLoggingThreadLocal; 5 | import org.minbox.framework.logging.core.GlobalLog; 6 | import org.minbox.framework.logging.core.GlobalLogLevel; 7 | import org.minbox.framework.util.StackTraceUtil; 8 | import org.springframework.util.ObjectUtils; 9 | 10 | /** 11 | * Global log memory mode storage implementation 12 | * 13 | * @author 恒宇少年 14 | */ 15 | public class GlobalLoggingMemoryStorage extends AbstractGlobalLogging { 16 | /** 17 | * collection debug level log 18 | * 19 | * @param msg log content 20 | */ 21 | @Override 22 | public void debug(String msg) { 23 | GlobalLog globalLog = buildGlobalLog(GlobalLogLevel.debug, msg); 24 | GlobalLoggingThreadLocal.addGlobalLogs(globalLog); 25 | } 26 | 27 | /** 28 | * collection debug level log 29 | * for example: 30 | * this is test log,value is {} 31 | * 32 | * @param format Unformatted log content 33 | * @param arguments List of parameters corresponding to log content 34 | */ 35 | @Override 36 | public void debug(String format, Object... arguments) { 37 | String log = replacePlaceholder(format, arguments); 38 | GlobalLog globalLog = buildGlobalLog(GlobalLogLevel.debug, log); 39 | GlobalLoggingThreadLocal.addGlobalLogs(globalLog); 40 | } 41 | 42 | @Override 43 | public void info(String msg) { 44 | GlobalLog globalLog = buildGlobalLog(GlobalLogLevel.info, msg); 45 | GlobalLoggingThreadLocal.addGlobalLogs(globalLog); 46 | } 47 | 48 | @Override 49 | public void info(String format, Object... arguments) { 50 | String log = replacePlaceholder(format, arguments); 51 | GlobalLog globalLog = buildGlobalLog(GlobalLogLevel.info, log); 52 | GlobalLoggingThreadLocal.addGlobalLogs(globalLog); 53 | } 54 | 55 | @Override 56 | public void error(String msg) { 57 | this.error(msg, java.util.Optional.ofNullable(null)); 58 | } 59 | 60 | @Override 61 | public void error(String msg, Throwable throwable) { 62 | GlobalLog globalLog = buildGlobalLog(GlobalLogLevel.error, msg); 63 | if (!ObjectUtils.isEmpty(throwable)) { 64 | String exceptionStack = StackTraceUtil.getStackTrace(throwable); 65 | globalLog.setExceptionStack(exceptionStack); 66 | } 67 | GlobalLoggingThreadLocal.addGlobalLogs(globalLog); 68 | } 69 | 70 | @Override 71 | public void error(String format, Object... arguments) { 72 | String log = replacePlaceholder(format, arguments); 73 | GlobalLog globalLog = buildGlobalLog(GlobalLogLevel.error, log); 74 | GlobalLoggingThreadLocal.addGlobalLogs(globalLog); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/java/org/minbox/framework/logging/admin/ui/HomepageForwardingFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.admin.ui; 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | import org.springframework.http.HttpHeaders; 23 | import org.springframework.http.MediaType; 24 | import org.springframework.web.util.UrlPathHelper; 25 | 26 | import javax.servlet.*; 27 | import javax.servlet.http.HttpServletRequest; 28 | import java.io.IOException; 29 | import java.util.List; 30 | 31 | /** 32 | * Home Page Forwarding Filter 33 | * 34 | * @author:恒宇少年 - 于起宇 35 | *

36 | * DateTime:2019-07-31 15:54 37 | * Blog:http://blog.yuqiyu.com 38 | * WebSite:http://www.jianshu.com/u/092df3f77bca 39 | * Gitee:https://gitee.com/hengboy 40 | * GitHub:https://github.com/hengboy 41 | */ 42 | public class HomepageForwardingFilter implements Filter { 43 | private static final Logger log = LoggerFactory.getLogger(HomepageForwardingFilter.class); 44 | private final String homepage; 45 | private final HomepageForwardingMatcher matcher; 46 | 47 | 48 | public HomepageForwardingFilter(String homepage, List routes) { 49 | this.homepage = homepage; 50 | UrlPathHelper urlPathHelper = new UrlPathHelper(); 51 | this.matcher = new HomepageForwardingMatcher<>( 52 | routes, 53 | HttpServletRequest::getMethod, 54 | urlPathHelper::getPathWithinApplication, 55 | r -> MediaType.parseMediaTypes(r.getHeader(HttpHeaders.ACCEPT)) 56 | ); 57 | } 58 | 59 | @Override 60 | public void doFilter(ServletRequest request, 61 | ServletResponse response, 62 | FilterChain chain) throws IOException, ServletException { 63 | if (request instanceof HttpServletRequest) { 64 | HttpServletRequest httpRequest = (HttpServletRequest) request; 65 | if (this.matcher.test(httpRequest)) { 66 | log.trace("Forwarding request with URL {} to index", httpRequest.getRequestURI()); 67 | request.getRequestDispatcher(this.homepage).forward(request, response); 68 | return; 69 | } 70 | } 71 | 72 | chain.doFilter(request, response); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/java/org/minbox/framework/logging/admin/ui/HomepageForwardingMatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.admin.ui; 19 | 20 | import org.springframework.http.HttpMethod; 21 | import org.springframework.http.MediaType; 22 | 23 | import java.util.List; 24 | import java.util.function.Function; 25 | import java.util.function.Predicate; 26 | import java.util.regex.Pattern; 27 | import java.util.stream.Collectors; 28 | 29 | /** 30 | * ApiBoot Logging Admin Ui Page Forwarding Matcher 31 | * 32 | * @author:恒宇少年 - 于起宇 33 | *

34 | * DateTime:2019-07-31 15:55 35 | * Blog:http://blog.yuqiyu.com 36 | * WebSite:http://www.jianshu.com/u/092df3f77bca 37 | * Gitee:https://gitee.com/hengboy 38 | * GitHub:https://github.com/hengboy 39 | */ 40 | public class HomepageForwardingMatcher implements Predicate { 41 | private final List routes; 42 | private final Function methodAccessor; 43 | private final Function pathAccessor; 44 | private final Function> acceptsAccessor; 45 | 46 | public HomepageForwardingMatcher(List routes, 47 | Function methodAccessor, 48 | Function pathAccessor, 49 | Function> acceptsAccessor) { 50 | this.routes = toPatterns(routes); 51 | this.methodAccessor = methodAccessor; 52 | this.pathAccessor = pathAccessor; 53 | this.acceptsAccessor = acceptsAccessor; 54 | } 55 | 56 | public boolean test(T request) { 57 | if (!HttpMethod.GET.matches(this.methodAccessor.apply(request))) { 58 | return false; 59 | } 60 | 61 | if (this.routes.stream().noneMatch(p -> p.matcher(this.pathAccessor.apply(request)).matches())) { 62 | return false; 63 | } 64 | 65 | return this.acceptsAccessor.apply(request).stream().anyMatch(t -> t.includes(MediaType.TEXT_HTML)); 66 | } 67 | 68 | private List toPatterns(List routes) { 69 | return routes.stream() 70 | .map(r -> "^" + r.replaceAll("/[*][*]", "(/.*)?") + "$") 71 | .map(Pattern::compile) 72 | .collect(Collectors.toList()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/admin/discovery/lb/support/SmoothWeightedRoundRobinStrategy.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.admin.discovery.lb.support; 2 | 3 | import org.minbox.framework.logging.client.MinBoxLoggingException; 4 | import org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceNode; 5 | 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | import java.util.concurrent.ConcurrentMap; 10 | import java.util.concurrent.locks.ReentrantLock; 11 | 12 | /** 13 | * The {@link org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceStrategy} Poll strategy 14 | * 15 | * @author 恒宇少年 16 | * @see DefaultLoadBalanceStrategy 17 | * @see org.minbox.framework.logging.client.admin.discovery.lb.LoadBalanceStrategy 18 | */ 19 | public class SmoothWeightedRoundRobinStrategy extends DefaultLoadBalanceStrategy { 20 | /** 21 | * load balance node {@link LoadBalanceNode} 22 | */ 23 | private ConcurrentMap nodes = new ConcurrentHashMap(); 24 | 25 | private ReentrantLock lock = new ReentrantLock(); 26 | 27 | /** 28 | * lookup load-balanced logging admin address {@link LoadBalanceNode#getAddress()} 29 | * lock admin address by {@link ReentrantLock} 30 | * 31 | * @param adminAddress logging admin address array 32 | * @return load-balanced logging admin address 33 | * @throws MinBoxLoggingException MinBox Logging Exception 34 | */ 35 | @Override 36 | public String lookup(String[] adminAddress) throws MinBoxLoggingException { 37 | List loadBalanceNodeList = initNodeList(adminAddress); 38 | loadBalanceNodeList.stream().forEach(loadBalanceNode -> nodes.put(loadBalanceNode.getAddress(), loadBalanceNode)); 39 | try { 40 | lock.lock(); 41 | return this.findMatchAddress(); 42 | } finally { 43 | lock.unlock(); 44 | } 45 | } 46 | 47 | /** 48 | * Find match logging admin address {@link LoadBalanceNode#getAddress()} 49 | * Obtaining the Node with the Largest Weight 50 | * 51 | * @return load-balanced logging admin address 52 | */ 53 | private String findMatchAddress() { 54 | int totalWeight = 0; 55 | LoadBalanceNode maxNode = null; 56 | int maxWeight = 0; 57 | Iterator iterator = nodes.keySet().iterator(); 58 | while (iterator.hasNext()) { 59 | LoadBalanceNode n = nodes.get(iterator.next()); 60 | totalWeight += n.getInitWeight(); 61 | n.setCurrentWeight(n.getCurrentWeight() + n.getInitWeight()); 62 | if (maxNode == null || maxWeight < n.getCurrentWeight()) { 63 | maxNode = n; 64 | maxWeight = n.getCurrentWeight(); 65 | } 66 | } 67 | maxNode.setCurrentWeight(maxNode.getCurrentWeight() - totalWeight); 68 | return maxNode.getAddress(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /minbox-logging-samples/logging-client-sample/src/main/java/org/minbox/framework/logging/client/sample/LoggingClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.minbox.framework.logging.client.sample; 2 | 3 | import org.minbox.framework.logging.client.LoggingFactoryBean; 4 | import org.minbox.framework.logging.client.admin.discovery.support.LoggingAppointAdminDiscovery; 5 | import org.minbox.framework.logging.client.global.GlobalLogging; 6 | import org.minbox.framework.logging.client.global.support.GlobalLoggingMemoryStorage; 7 | import org.minbox.framework.logging.client.interceptor.web.LoggingWebInterceptor; 8 | import org.minbox.framework.logging.client.span.LogSpanIdGenerator; 9 | import org.minbox.framework.logging.client.tracer.LogTraceIdGenerator; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 14 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 15 | 16 | /** 17 | * Logging Client 配置 18 | * 19 | * @author 恒宇少年 20 | */ 21 | @Configuration 22 | public class LoggingClientConfiguration implements WebMvcConfigurer { 23 | /** 24 | * Logging Client提供的日志拦截器 {@link LoggingWebInterceptor} 25 | */ 26 | @Autowired 27 | private LoggingWebInterceptor loggingWebInterceptor; 28 | 29 | /** 30 | * 注册使用拦截器 31 | * 32 | * @param registry 33 | */ 34 | @Override 35 | public void addInterceptors(InterceptorRegistry registry) { 36 | registry.addInterceptor(loggingWebInterceptor).addPathPatterns("/**"); 37 | } 38 | 39 | /** 40 | * 初始化{@link LoggingFactoryBean} 41 | * 42 | * @return {@link LoggingFactoryBean} 43 | */ 44 | @Bean 45 | public LoggingFactoryBean loggingFactoryBean() { 46 | LoggingFactoryBean factoryBean = new LoggingFactoryBean(); 47 | // 设置自定义生成traceId 48 | factoryBean.setTraceGenerator(customerTraceGenerator()); 49 | // 设置自定义生成spanId 50 | factoryBean.setSpanGenerator(customerSpanGenerator()); 51 | // 设置在控制台输出日志 52 | factoryBean.setShowConsoleLog(true); 53 | // 格式化控制台输出的日志 54 | factoryBean.setFormatConsoleLog(true); 55 | factoryBean.setLoggingAdminDiscovery( 56 | new LoggingAppointAdminDiscovery(new String[]{"user:123456@localhost:9091"}) 57 | ); 58 | return factoryBean; 59 | } 60 | 61 | /** 62 | * 自定义生成traceId 63 | * 64 | * @return {@link LogTraceIdGenerator} 65 | */ 66 | @Bean 67 | public LogTraceIdGenerator customerTraceGenerator() { 68 | return new CustomerTraceIdGenerator(); 69 | } 70 | 71 | /** 72 | * 自定义生成spanId 73 | * 74 | * @return 75 | */ 76 | @Bean 77 | public LogSpanIdGenerator customerSpanGenerator() { 78 | return new CustomerSpanIdGenerator(); 79 | } 80 | 81 | @Bean 82 | public GlobalLogging globalLogging() { 83 | return new GlobalLoggingMemoryStorage(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/services/application.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 axios, {redirectOn401} from '@/utils/axios'; 18 | import waitForPolyfill from '@/utils/eventsource-polyfill'; 19 | import {concat, from, ignoreElements, Observable} from '@/utils/rxjs'; 20 | import uri from '@/utils/uri'; 21 | import sortBy from 'lodash/sortBy'; 22 | import Instance from './instance'; 23 | 24 | const actuatorMimeTypes = [ 25 | 'application/vnd.spring-boot.actuator.v2+json', 26 | 'application/vnd.spring-boot.actuator.v1+json', 27 | 'application/json' 28 | ]; 29 | 30 | export const hasMatchingContentType = (contentType, compatibleContentTypes) => 31 | Boolean(contentType) && compatibleContentTypes.includes(contentType.replace(/;.*$/, '')); 32 | 33 | export const throwOnError = (responses) => responses.forEach(r => { 34 | if (r.status >= 400) { 35 | const error = new Error(`Request for Instance '${r.instanceId}' failed with status ${r.status}`); 36 | error.responses = responses; 37 | throw error 38 | } 39 | }); 40 | 41 | export const convertBody = (responses) => responses.map(res => { 42 | if (res.body && hasMatchingContentType(res.contentType, actuatorMimeTypes)) { 43 | return { 44 | ...res, 45 | body: JSON.parse(res.body) 46 | } 47 | } 48 | return res; 49 | }); 50 | 51 | class Application { 52 | constructor({name, instances, ...application}) { 53 | Object.assign(this, application); 54 | this.name = name; 55 | this.axios = axios.create({ 56 | baseURL: uri`applications/${this.name}/`, 57 | }); 58 | this.axios.interceptors.response.use(response => response, redirectOn401() 59 | ); 60 | this.instances = sortBy(instances.map(i => new Instance(i), [instance => instance.registration.healthUrl])); 61 | } 62 | 63 | filterInstances(predicate) { 64 | return new Application({ 65 | ...this, 66 | instances: this.instances.filter(predicate) 67 | }) 68 | } 69 | 70 | findInstance(instanceId) { 71 | return this.instances.find(instance => instance.id === instanceId); 72 | } 73 | 74 | get isUnregisterable() { 75 | return this.instances.findIndex(i => i.isUnregisterable) >= 0; 76 | } 77 | 78 | async unregister() { 79 | return this.axios.delete('', { 80 | headers: {'Accept': 'application/json'} 81 | }) 82 | } 83 | 84 | 85 | static _transformResponse(data) { 86 | if (!data) { 87 | return data; 88 | } 89 | const json = JSON.parse(data); 90 | if (json instanceof Array) { 91 | const applications = json.map(j => new Application(j)); 92 | return sortBy(applications, [item => item.name]); 93 | } 94 | return new Application(json); 95 | } 96 | } 97 | 98 | export default Application; 99 | -------------------------------------------------------------------------------- /minbox-logging-client/src/main/java/org/minbox/framework/logging/client/filter/LoggingBodyFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright [2019] [恒宇少年 - 于起宇] 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 | * http://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 | 18 | package org.minbox.framework.logging.client.filter; 19 | 20 | import org.minbox.framework.logging.client.LoggingFactoryBean; 21 | import org.minbox.framework.util.UrlUtils; 22 | import org.minbox.framework.web.request.RequestWrapper; 23 | import org.minbox.framework.web.response.ResponseWrapper; 24 | import org.minbox.framework.web.util.HttpRequestUtil; 25 | 26 | import javax.servlet.*; 27 | import javax.servlet.annotation.WebFilter; 28 | import javax.servlet.http.HttpServletRequest; 29 | import javax.servlet.http.HttpServletResponse; 30 | import java.io.IOException; 31 | 32 | /** 33 | * ApiBoot Logging Body(Request / Response) Filter 34 | * Encapsulation principal obtains the corresponding replicated content 35 | * 36 | * @author 恒宇少年 37 | */ 38 | @WebFilter(urlPatterns = "/*", filterName = "loggingBodyFilter") 39 | public class LoggingBodyFilter implements Filter { 40 | /** 41 | * the bean name of {@link LoggingBodyFilter} 42 | */ 43 | public static final String BEAN_NAME = "loggingBodyFilter"; 44 | /** 45 | * {@link LoggingFactoryBean} 46 | */ 47 | private LoggingFactoryBean factoryBean; 48 | 49 | public LoggingBodyFilter(LoggingFactoryBean factoryBean) { 50 | this.factoryBean = factoryBean; 51 | } 52 | 53 | /** 54 | * Wrapper Body 55 | * replace http request body instance 56 | * replace http response body instance 57 | * 58 | * @param request http request 59 | * @param response http response 60 | * @param filterChain filter chain 61 | * @throws IOException ioException 62 | * @throws ServletException servlet Exception 63 | */ 64 | @Override 65 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { 66 | // see https://github.com/minbox-projects/api-boot/issues/85 67 | HttpServletRequest servletRequest = (HttpServletRequest) request; 68 | String uri = HttpRequestUtil.getUri(servletRequest); 69 | // see https://gitee.com/minbox-projects/minbox-logging/issues/I1JWSK 70 | if (!HttpRequestUtil.isMultipart(request) && !UrlUtils.isIgnore(factoryBean.getIgnorePaths(), uri)) { 71 | RequestWrapper requestWrapper = new RequestWrapper(servletRequest); 72 | ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response); 73 | filterChain.doFilter(requestWrapper, responseWrapper); 74 | responseWrapper.flushBuffer(); 75 | } else { 76 | filterChain.doFilter(request, response); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /minbox-logging-admin-ui/src/main/frontend/store.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2019 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 | * http://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 | import Application from '@/services/application'; 17 | import {bufferTime, concat, concatMap, defer, delay, filter, map, retryWhen, tap} from '@/utils/rxjs'; 18 | 19 | export default class { 20 | constructor() { 21 | this._listeners = {}; 22 | this._applications = new Map(); 23 | this.applications = []; 24 | this.applications.findInstance = (instanceId) => { 25 | for (let application of this.applications) { 26 | const instance = application.findInstance(instanceId); 27 | if (instance) { 28 | return instance; 29 | } 30 | } 31 | return undefined; 32 | }; 33 | this.applications.findApplicationForInstance = (instanceId) => { 34 | return this.applications.find(application => Boolean(application.findInstance(instanceId))); 35 | }; 36 | } 37 | 38 | addEventListener(type, listener) { 39 | if (!(type in this._listeners)) { 40 | this._listeners[type] = []; 41 | } 42 | this._listeners[type].push(listener); 43 | } 44 | 45 | removeEventListener(type, listener) { 46 | if (!(type in this._listeners)) { 47 | return; 48 | } 49 | 50 | const idx = this._listeners[type].indexOf(listener); 51 | if (idx > 0) { 52 | this._listeners[type].splice(idx, 1); 53 | } 54 | } 55 | 56 | _dispatchEvent(type, ...args) { 57 | if (!(type in this._listeners)) { 58 | return; 59 | } 60 | const target = this; 61 | this._listeners[type].forEach( 62 | listener => listener.call(target, ...args) 63 | ) 64 | } 65 | 66 | start() { 67 | 68 | } 69 | 70 | updateApplications(applications) { 71 | applications.forEach(a => this.updateApplication(a)); 72 | this.applications.splice(0, this.applications.length, ...Array.from(this._applications.values())); 73 | } 74 | 75 | updateApplication(application) { 76 | const oldApplication = this._applications.get(application.name); 77 | if (!oldApplication && application.instances.length > 0) { 78 | this._applications.set(application.name, application); 79 | this._dispatchEvent('added', application); 80 | } else if (oldApplication && application.instances.length > 0) { 81 | this._applications.set(application.name, application); 82 | this._dispatchEvent('updated', application, oldApplication); 83 | } else if (oldApplication && application.instances.length <= 0) { 84 | this._applications.delete(application.name); 85 | this._dispatchEvent('removed', oldApplication); 86 | } 87 | } 88 | 89 | stop() { 90 | if (this.subscription) { 91 | try { 92 | !this.subscription.closed && this.subscription.unsubscribe(); 93 | } finally { 94 | this.subscription = null; 95 | } 96 | } 97 | } 98 | } 99 | --------------------------------------------------------------------------------