分类目录组件项目

Kurento

主页: http://www.kurento.org/
github: https://github.com/kurento
服务端采用C++实现: https://github.com/Kurento/kurento-media-server
Docker https://hub.docker.com/r/kurento/kurento-media-server
说明文档 https://doc-kurento.readthedocs.io/en/stable/

Kurento模块分为三类:
主要模块与Kurento Media Server开箱即用合并:
kms-core:Kurento Media Server的主要组件。
kms-elements:Kurento Media Elements的实现(WebRtcEndpoint,PlayerEndpoint等)
kms-filters:
Kurento过滤器的实现(FaceOverlayFilter,ZBarFilter等)
内置模块Kurento团队开发的额外模块,用于增强Kurento Media Server的基本功能。到目前为止,有四个内置模块,分别是:
kms-platedetector:用于检测视频流中的车牌的过滤器。
kms-pointerdetector:基于颜色跟踪检测视频流中指针的过滤器。
kms-chroma:过滤器,它在顶层使用颜色范围并使之透明,从而在后面显示另一个图像。
kms-crowddetector:用于检测视频流中人聚集的过滤器。
定制模块

 docker run --name kms -d -p 8888:8888 \
  -e KMS_STUN_IP= \
  -e KMS_STUN_PORT=3478 \
  -e KMS_TURN_URL=user@password:urlorIp:3478 \
   kurento/kurento-media-server:latest

  -e KMS_NETWORK_INTERFACES= \
  -e KMS_EXTERNAL_ADDRESS= \
  -e KMS_MIN_PORT= \
  -e KMS_MAX_PORT= \
  -e KMS_MTU=1200 \
    kurento/kurento-media-server:latest
配制文件位置
/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini
/etc/kurento/modules/kurento/BaseRtpEndpoint.conf.ini
#查看KMS日志
docker logs kms
#实时查看:
docker logs -f kms
日志输出
    docker logs --follow kms >"kms-$(date '+%Y%m%dT%H%M%S').log" 2>&1

    检查KMS是否已启动并正在侦听连接,请使用以下命令:
curl \
    --include \
    --header "Connection: Upgrade" \
    --header "Upgrade: websocket" \
    --header "Host: 127.0.0.1:8888" \
    --header "Origin: 127.0.0.1" \
    http://127.0.0.1:8888/kurento
应该得到类似于以下内容的响应:
HTTP/1.1 500 Internal Server Error
Server: WebSocket++/0.7.0

#进入镜像
docker exec -it kms /bin/bash
#安装vim
apt-get update
apt-get install vim
#进入配置文件夹
cd /etc/kurento/modules/kurento/
#编辑配置文件
vim WebRtcEndpoint.conf.ini
stunServerAddress=xx.xx.xx.xx
stunServerPort=pp
turnURL=username:userpwd@xx.xx.xx.xx:pp?transport=tcp
or
修改docker运行的kms配置文件方法
1.复制容器中的 配置文件到 宿主机中
docker cp  kms:/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini  ~/WebRtcEndpoint.conf.ini
2.修改配置文件
vim ~/WebRtcEndpoint.conf.ini
3.宿主机配置文件 复制到 kms容器中
 docker cp ~/WebRtcEndpoint.conf.ini kms:/etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini

#查看当前启动的容器
docker ps
docker restart  {kurento容器ID}

kurento相关配置
1、Kurento Media Server 日志
Kurento Media Server日志文件存储在 /var/log/kurento-media-server/文件夹中。 此文件夹的内容如下:
    media-server_.<log_number>.<kms_pid>.log: Kurento Media Server的当前日志
    media-server_error.log: 第三方错误
    logs: 包含KMS已旋转日志的文件夹
2、Kurento Media Server 配置
    /etc/default/kurento-media-server 默认配置
    /etc/kurento/kurento.conf.json 通用配置
    /etc/kurento/modules/kurento/MediaElement.conf.ini Media Elements 通用参数。
    /etc/kurento/modules/kurento/SdpEndpoint.conf.ini SdpEndpoints的音频/视频参数( 例如: WebRtcEndpoint and RtpEndpoint)。
    /etc/kurento/modules/kurento/WebRtcEndpoint.conf.ini WebRtcEndpoint 特定参数。
    /etc/kurento/modules/kurento/HttpEndpoint.conf.ini HttpEndpoint 特定参数。

#### kurento-hello-world
““
git clone https://github.com/Kurento/kurento-tutorial-java.git
cd kurento-tutorial-java/kurento-hello-world
vim src/main/resources/static/js/index.js
在函数function uiStart()里,增加一个叫iceservers的变量,格式如下:
var iceservers={
“iceServers”:[
{
urls:”stun:xx.xx.xx.xx:3478″
},
{
urls:[“turn:xx.xx.xx.xx:3478″]
username:”xxxx”,
credential: “xxxx”
}
]
}
再修改底下的options变量:
const options = {
localVideo: uiLocalVideo,
remoteVideo: uiRemoteVideo,
mediaConstraints: { audio: true, video: true },
onicecandidate: (candidate) => sendMessage({
id: ‘ADD_ICE_CANDIDATE’,
candidate: candidate,
}),
configuration: iceservers //修改在这里,增加了一个configuration的key
};

启动项目
mvn -U clean spring-boot:run -Dkms.url=ws://xx.xx.xx.xx:8888/kurento

用 idea 打开 kurento-hello-world 项目,下载 maven 依赖完成后,在 run configurations 中添加 new configurations。
选择 maven , command line 中输入:
spring-boot:run -Dkms.url=ws://:8888/kurento # 这里的 public-ip 添你安装 kms 的服务器公网 ip 地址

启动完之后用谷歌或者火狐浏览器打开demo页面https://localhost:8443/
点击start启动

运行 hello world 示例时,会遇到 使用websocket传输内容过长的问题
//项目中创建 package org.kurento.tutorial.helloworld.config
//config 包下创建类
package org.kurento.tutorial.helloworld.config;

@Configuration
//@ComponentScan
//@EnableAutoConfiguration
public class WebAppRootContext implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println(“org.apache.tomcat.websocket.textBufferSize”);
servletContext.addListener(WebAppRootListener.class);
servletContext.setInitParameter(“org.apache.tomcat.websocket.textBufferSize”,”1024000″);
}

}
““

API Java SDK for Kurento Media Server

https://github.com/Kurento/kurento-java

Kurento tutorials for Node JS

https://github.com/Kurento/kurento-tutorial-node

信令服务器与web客户端 kurento-room

https://github.com/Kurento/kurento-room

NUBOMEDIA

NUBOMEDIA Autonomous Installer
https://nubomedia.readthedocs.io/en/latest/tools/autonomous-installer/

Android客户端开源库

https://github.com/nubomedia-vtt/nubo-test

iOS客户端开源库

https://github.com/nubomediaTI/Kurento-iOS

ffmpeg转发模块

利用ffmpeg可执行文件将本地RTP流封装转发成RTMP推送出去,具体可以参考这个开源工程:
kurento-rtmp https://github.com/godka/kurento-rtmp

gstreamer转发模块

RTP解包 —— 音视频转换 —— FLV封包 —— RTMP推流

coTrun

https://github.com/coturn/coturn
https://github.com/bprodoehl/docker-turnserver
带有Coturn STUN和TURN server (https://github.com/coturn/coturn)的Docker容器,
ocker run -d -e EXTERNAL_IP=1.2.3.4 –name=turnserver –restart=”on-failure:10″ –net=host -p 3478:3478 -p 3478:3478/udp bprodoehl/turnserver
环境参数
SKIP_AUTO_IP-绑定到地址,当与–net =host一起运行时,对IPv4和IPv6双协议栈很有用,EXTERNAL_IP –可选手动指定的外部IP地址端口–监听端口用于STUN和TURNLISTEN_ON_PUBLIC_IP –绑定到外部IPUSE_IPV4 –在确定外部IP时强制IPv4

下载安装

一、ubuntu安装软件包
# apt install coturn

二、配置coturnls
1、复制DTLS、TLS支持的证书文件:
# cp/usr/share/coturn/examples/etc/turn_server_cert.pem /etc/turn_server_cert.pem
# cp/usr/share/coturn/examples/etc/turn_server_pkey.pem /etc/turn_server_pkey.pem
2、编辑/etc/turnserver.conf文件:
listening-port=3478
tls-listening-port=5349
listening-ip=192.168.1.230
external-ip=47.104.19.243(NAT必须)
lt-cred-mech
user=tcp:123456(必须)
realm=example.com(必须)
3、编辑/etc/default/coturn文件:
TURNSERVER_ENABLED=1(必须)

三、完成安装
1、重启coturn
# service coturn restart

2、测试验证
# turnadmin -a -u test -r leifeng-elec.com-p test
# turnutils_uclient 192.168.1.230 -u test -wtest

可以先安装环境
sudo apt-get install libssl-dev
sudo apt-get install libevent-dev
sudo apt-get install libpq-dev
sudo apt-get install mysql-client
sudo apt-get install libmysqlclient-dev
sudo apt-get install libhiredis-dev
sudo apt-get install git

git clone https://github.com/coturn/coturn
./configure --prefix=/usr/local/coturn
make && make install

1) If your system supports automatic start-up system daemon services, 
then to enable the turnserver as a system service that is automatically
started, you have to:

    a) Create and edit /etc/turnserver.conf or 
    /usr/local/etc/turnserver.conf . 
    Use /usr/local/etc/turnserver.conf.default as an example.

    b) For user accounts settings: set up SQLite or PostgreSQL or 
    MySQL or MongoDB or Redis database for user accounts.
    Use /usr/local/share/turnserver/schema.sql as SQL database schema,
    or use /usr/local/share/turnserver/schema.userdb.redis as Redis
    database schema description and/or 
    /usr/local/share/turnserver/schema.stats.redis
    as Redis status & statistics database schema description.

    If you are using SQLite, the default database location is in 
    /var/db/turndb or in /usr/local/var/db/turndb or in /var/lib/turn/turndb.

    c) add whatever is necessary to enable start-up daemon for the 
    /usr/local/bin/turnserver.

2) If you do not want the turnserver to be a system service, 
   then you can start/stop it "manually", using the "turnserver" 
   executable with appropriate options (see the documentation).

3) To create database schema, use schema in file 
/usr/local/share/turnserver/schema.sql.

4) For additional information, run:

   $ man turnserver
   $ man turnadmin
   $ man turnutils

ERROR: OpenSSL Crypto development libraries are not installed properly in required location.
apt-get install libssl-dev

生成md5码:turnadmin -k –u 用户名 -r nanjing -p 密码

生成证书
sudo openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 -nodes

创建turnuserdb.conf文件
vi /etc/turnuserdb.conf
在其中填入之前生成的用户名和key

配制参数 编辑文件/etc/turnserver.conf
listening-port=3478
external-ip=公网IP
user=username:password
realm=域名
以上常用,以下按需
listening-device=填写自己的网卡类型
relay-device=填写自己的网卡类型
listening-ip=ip地址
listening-port=3478
tls-listening-port=5349
listening-ip与relay-ip采用内网ip,external-ip是外网的ip
relay-ip=ip地址
external-ip=ip地址
relay-threads=50
lt-cred-mech
static-auth-secret=用户名
user=用户名:密钥
userdb=/etc/turnuserdb.conf
#max-bps=102400
pidfile="/var/run/turnserver.pid"
no-loopback-peers
no-multicast-peers
sha256
mobility
no-cli
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
stale-nonce
use-auth-secret
Verbose
fingerprint

运行:
sudo turnserver -L 23.83.233.168 -o -a -b /etc/turnuserdb.conf -f -r nanjing

修改信令连接
 var pcConfig = {
            'iceServers': [
                {
                    'url': 'stun:xx.xx.xx.xxip:3478',
                },
                {
                    'url': 'stun:stun.xx.xx.xx.xxip:3478',
                },
                {
                'urls': 'turn:xxx.cn:3478',
                'credential': "mypasswd", or 密钥
                'username': "myname"
            }]
        };

可以根据需要调整其他参数。有关更多信息,请查看Coturn帮助页面:
https://github.com/coturn/coturn/wiki/turnserver
https://github.com/coturn/coturn/wiki/CoturnConfig
编辑文件/etc/default/coturn并取消注释TURNSERVER_ENABLED=1,以便TURN服务器自动启动为系统服务守护程序。

在防火墙中打开以下端口:
3478 TCP和UDP。
49152 – 65535 UDP:按照 RFC 5766,这些是TURN服务器用于交换媒体的端口。可以使用TURN服务器上的min-port和max-port参数更改这些端口。
注意
虽然RFC指定了TURN使用的端口,但如果使用STUN,则需要打开所有UDP端口,因为STUN不会限制可能使用的端口范围。

测试地址
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/

socket.io for java

Server

<dependency>
      <groupId>com.corundumstudio.socketio</groupId>
      <artifactId>netty-socketio</artifactId>
      <version>1.7.16</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>1.7.2</version>
    </dependency>

public class ServerStart {

    public static void main(String [] args){
        Configuration config = new Configuration();
        config.setHostname("localhost");
        config.setPort(9999);
        SocketIOServer server = new SocketIOServer(config);
        server.addConnectListener(new ConnectListener() {
            // 添加客户端连接监听器
            public void onConnect(SocketIOClient client) {
                //logger.info(client.getRemoteAddress() + " web客户端接入");
                //不知道如何与客户端对应,好的办法是自己去写对应的函数
                client.sendEvent("connected", "hello");
            }
        });

        //监听客户端事件,client_info为事件名称,-自定义事件
         server.addEventListener("client_info", String.class, new DataListener<String>(){
            public void onData(SocketIOClient client, String data, AckRequest ackRequest) throws ClassNotFoundException {
                //客户端推送advert_info事件时,onData接受数据,这里是string类型的json数据,还可以为Byte[],object其他类型
                String sa = client.getRemoteAddress().toString();
                String clientIp = sa.substring(1,sa.indexOf(":"));//获取客户端连接的ip
                Map params = client.getHandshakeData().getUrlParams();//获取客户端url参数
                System.out.println(clientIp+":客户端:************"+data);
            }
         });

        //添加客户端断开连接事件
        server.addDisconnectListener(new DisconnectListener(){
            public void onDisconnect(SocketIOClient client) {
                String sa = client.getRemoteAddress().toString();
                String clientIp = sa.substring(1,sa.indexOf(":"));//获取设备ip
                System.out.println(clientIp+"-------------------------"+"客户端已断开连接");
                //给客户端发送消息
                client.sendEvent("advert_info",clientIp+"客户端你好,我是服务端,期待下次和你见面");
            }
        });
        server.start();

        while (true){
            try {
                Thread.sleep(1500);
                //广播消息
                server.getBroadcastOperations().sendEvent("borcast","are you live?");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Client

        <dependency>
            <groupId>io.socket</groupId>
            <artifactId>socket.io-client</artifactId>
            <version>1.0.0</version>
        </dependency>

public class AppStart {

    public static void main(String [] args){
        String url ="http://localhost:9999";
        try{
            IO.Options options = new IO.Options();
            options.transports = new String[]{"websocket"};
            options.reconnectionAttempts = 2;
            options.reconnectionDelay = 1000;//失败重连的时间间隔
            options.timeout = 500;//连接超时时间(ms)
            //par1 是任意参数
            final Socket socket = IO.socket(url+"?par1=1234", options);

            socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {

                public void call(Object... args) {
                    socket.send("hello");
                }
            });

            //自定义事件
            socket.on("borcast", new Emitter.Listener() {
                public void call(Object... objects) {
                    System.out.println("receive borcast data:" + objects[0].toString());
                }
            });

            socket.on("connected", new Emitter.Listener() {
                public void call(Object... objects) {
                    System.out.println("receive connected data:" + objects[0].toString());
                }
            });

            socket.connect();
            //循环发送数据
            while (true){
                socket.emit("client_info"," 客户端在发送数据");
                Thread.sleep(2000);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

VUE
https://www.npmjs.com/package/vue-socket.io

import VueSocketIO from 'vue-socket.io'
import SocketIO from 'socket.io-client'

Vue.use(new VueSocketIO({
  debug: true,
  connection: SocketIO('http://192.168.88.108:443', {
    path: '', // path千万不要写“/”
    transports: ['websocket', 'xhr-polling', 'jsonp-polling']
  }) // options object is Optional
}))

Other https://github.com/probil/vue-socket.io-extended

import Vue from 'vue'
import VueSocketIOExt from 'vue-socket.io-extended'
import SocketIO from 'socket.io-client';

const socket = SocketIO('https://localhost');
export default ({ store }) => {
  Vue.use(VueSocketIOExt, socket, { store });
}

sockets: {
      // 创建连接
      connect() {
        console.log('连接成功啦')
      },
      // 监听断开连接,函数
      disconnect() {
        console.log('断开服务器连接');
        this.connectdisabled = false;
        this.leavedisabled = true;
        this.senddisabled = true;
        this.inputdisabled = true;
      },
      reconnect() {
        console.log("重新链接");
      },
      // 监听自定义事件,需与服务端emit事件名一致
      joined(room, id) {
        console.log('joined',room, id)
        this.connectdisabled = true;
        this.leavedisabled = false;
        this.senddisabled = false;
        this.inputdisabled = false;
      },

//发送加入信令
this.$socket.client.emit('join', this.room)

WebRtc

https://appr.tc/

WebRTC adapter.js
github地址为:https://github.com/webrtc/adapter.
FYI: http://www.vue5.com/webrtc/webrtc.html
主要功能是隐藏像webkitRTCPeerConnection和mozRTCPeerConnection这样的前缀差异,并提供函数将MediaStream附加到HTML的或元素。
– 直接在代码中加入https://webrtc.github.io/adapter/adapter-latest.js
– npm install webrtc-adapter
使用时在JavaScript文件中加入一个模块
const adapter = require(‘webrtc-adapter’);
加载完成后既可以使用,例如可使用
console.log(adapter.browserDetails.browser);
or
import adapter from ‘webrtc-adapter’;
“child_process”: “^1.0.2”,
“fs”: “0.0.1-security”,
“webrtc-adapter”: “^7.5.1”,
“window”: “^4.2.7”
“net”: “^1.0.2”,
“tls”: “0.0.1”,

vue socket.io的github地址:https://github.com/MetinSeylan/Vue-Socket.io

npm install vue-socket.io --save
npm install socket.io-client --save

chrome里无法正常触发vue-socket.io中的connect回调,vue-socket.io使用到了大量es6的语法,考虑到原生es6在浏览器中的兼容性,导入babel-loader(nuxt cli中没有自带),
{src: ‘@/plugins/vue-socket.io’, ssr: false}

webSocket连接的地址是固定的

在main.js中直接这样写
    Vue.use(new VueSocketIO({
      debug: true,
      connection: 'socket地址:端口号',
      vuex: {       // 不需要用到vuex这个可以不加
            store,
            actionPrefix: 'SOCKET_',
            mutationPrefix: 'SOCKET_'
      }
}))

socket可以与vuex结合使用

import store from'./yourstore'
Vue.use(VueSocketio,socketio('http://socketserver.com:1923'), store);

socket地址是静态的写法

mounted(){
this.$socket.emit('connect', 1)
}

npm install –save-dev @gauseen/nuxt-proxy
// nuxt.config.js

modules: [
// 请求代理配置,解决跨域
‘@gauseen/nuxt-proxy’,
],
proxyTable: {
‘/api’: { target: ‘http://example.com’, ws: false }
},
注:
/api ———————— 每个接口特定标识字段 [String]
target —————— 目标代理服务 [String]
ws —————————— 是否支持 websocket 代理 [Boolean]

Spring Cloud Gateway

依赖
<!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
配制
spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false # true 之前的http://localhost:8081/service-consumer/user/info这样的请求地址也能正常访问,因为这时为每个服务创建了2个router。
          lower-case-service-id: true #转换服务id为小写
      routes:
        - id: service_nacos
          uri: lb://nacos #(注册中心中服务的名称)即service-consumer服务的负载均衡地址,并用StripPrefix的filter 在转发之前将/consumer去掉。
          predicates:
            - Path= /nacos/** #将以/consumer/**开头的请求都会转发到uri为lb://service-consumer的地址上
          filters:
            - StripPrefix=1

Gateway 过滤器

Spring Cloud Gateway的filter生命周期不像Zuul那么丰富,它只有两个:“pre”和“post”:

pre:这种过滤器在请求被路由之前调用。可以利用这个过滤器实现身份验证、在集群中选择请求的微服务、记录调试的信息。

post:这种过滤器在路由到服务器之后执行。这种过滤器可用来为响应添加HTTP Header、统计信息和指标、响应从微服务发送给客户端等。

Spring Cloud gateway的filter分为两种:GatewayFilter和Globalfilter。GlobalFilter会应用到所有的路由上,而Gatewayfilter将应用到单个路由或者一个分组的路由上。

利用Gatewayfilter可以修改请求的http的请求或者是响应,或者根据请求或者响应做一些特殊的限制。更多时候可以利用Gatewayfilter做一些具体的路由配置。

Gateway请求匹配

Gateway网关可以根据不同的方式进行匹配进而把请求分发到不同的后端服务上。

Gateway熔断

Spring Cloud Gateway也可以利用Hystrix的熔断特性,在流量过大时进行服务降级,同时项目中必须加上Hystrix的依赖。

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

Gateway重试路由器

Retry GatewayFilter通过四个参数来控制重试机制,参数说明如下:

retries:重试次数,默认值是 3 次。

statuses:HTTP 的状态返回码,取值请参考:org.springframework.http.HttpStatus。

methods:指定哪些方法的请求需要进行重试逻辑,默认值是 GET 方法,取值参考:org.springframework.http.HttpMethod。

series:一些列的状态码配置,取值参考:org.springframework.http.HttpStatus.Series。符合的某段状态码才会进行重试逻辑,默认值是 SERVER_ERROR,值是 5,也就是 5XX(5 开头的状态码),共有5个值。

使用上述配置进行测试,当后台服务不可用时,会在控制台看到请求三次的日志,证明此配置有效。

Gateway 限流操作

Spring Cloud Gateway本身集成了限流操作,Gateway限流需要使用Redis,pom文件中添加Redis依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
配置了Redis的信息,并配置了RequestRateLimiter的限流过滤器,该过滤器需要配置三个参数:
    BurstCapacity:令牌桶的总容量。
    replenishRate:令牌通每秒填充平均速率。
    Key-resolver:用于限流的解析器的Bean对象的名字。它使用SpEL表达式#{@beanName}从Spring容器中获取bean对象。
    注意:filter下的name必须是RequestRateLimiter。
Key-resolver参数后面的bean需要自己实现,然后注入到Spring容器中。KeyResolver需要实现resolve方法,比如根据ip进行限流,则需要用hostAddress去判断。

自定义Gatewayfilter

Spring Cloud Gateway自定义过滤器,过滤器需要实现GatewayFilter和Ordered这两个接口。
再将该过滤器注册到router中

    private static final Log log = LogFactory.getLog(GatewayFilter.class);
    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                    if (startTime != null) {
                        log.info("请求路径:"+exchange.getRequest().getURI().getRawPath() + "消耗时间: " + (System.currentTimeMillis() - startTime) + "ms");
                    }
                })
        );
    }
    @Override
    public int getOrder() {
        return 0;
    }
}
注册
    @Bean
        public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
            return builder.routes()
                    .route(r -> r.path("/user/**")
                            .filters(f -> f.filter(new RequestTimeFilter())
                                    .addResponseHeader("X-Response-Default-Foo", "Default-Bar"))
                            .uri("http://localhost:8504/user/info")
                            .order(0)
                            .id("customer_filter_router")
                    )
                    .build();
        }
除了上述代码的方式配置我们自定义的过滤器的方式之外,也可以在application.yml文件中直接配置

自定义GlobalFilter

Spring Cloud Gateway根据作用范围分为GatewayFilter和GlobalFilter,二者区别如下:

GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上。
GlobalFilter:全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,系统初始化时加载,并作用在每个路由上。
public class TokenFilter implements GlobalFilter, Ordered {
    Logger logger= LoggerFactory.getLogger( TokenFilter.class );
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            logger.info( "token 为空,无法进行访问." );
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

rancher 负载均衡时 default backend – 404

Nacos

官方网址:http://nacos.io
官网教程

docker

https://github.com/nacos-group/nacos-docker.git
https://hub.docker.com/r/nacos/nacos-server/tags?page=1&ordering=last_updated
docker pull nacos/nacos-server:2.0.0
docker pull nacos/nacos-server:latest

单机内存
docker run --name nacos-standalone -e MODE=standalone -p 8848:8848 -d --restart=always nacos/nacos-server:2.0.0
单机Mysql
docker run -d \
--name nacos-server \
-e PREFER_HOST_MODE=hostname \
-e MODE=standalone \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e MYSQL_MASTER_SERVICE_HOST=172.16.0.17 \
-e MYSQL_MASTER_SERVICE_PORT=3306 \
-e MYSQL_MASTER_SERVICE_USER=root \
-e MYSQL_MASTER_SERVICE_PASSWORD=root \
-e MYSQL_MASTER_SERVICE_DB_NAME=nacos \
-e MYSQL_SLAVE_SERVICE_HOST=192.168.1.3 \
-e MYSQL_SLAVE_SERVICE_PORT=3306 \
-p 8848:8848 \
--restart=always \
nacos/nacos-server:2.0.0

mkdir logs
mkdir properties
vi custom.properties

server.contextPath=/nacos
server.servlet.contextPath=/nacos
server.port=8848

spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://172.16.0.17:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=PW

nacos.cmdb.dumpTaskInterval=3600
nacos.cmdb.eventTaskInterval=10
nacos.cmdb.labelTaskInterval=300
nacos.cmdb.loadDataAtStart=false

management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false

server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i

nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health/**,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**,/v1/console/server/**
nacos.naming.distro.taskDispatchThreadCount=1
nacos.naming.distro.taskDispatchPeriod=200
nacos.naming.distro.batchSyncKeyCount=1000
nacos.naming.distro.initDataRatio=0.9
nacos.naming.distro.syncRetryDelay=5000
nacos.naming.data.warmup=true
nacos.naming.expireInstance=true

docker  run \
--name nacos -d \
-p 8848:8848 \
--privileged=true \
--restart=always \
-e JVM_XMS=256m \
-e JVM_XMX=256m \
-e MODE=standalone \
-e PREFER_HOST_MODE=hostname \
-v ~/nacos/logs:/home/nacos/logs \
-v ~/nacos/custom.properties:/home/nacos/init.d/custom.properties \
nacos/nacos-server:2.0.0

2.下载源码或者安装包

你可以通过源码和发行包两种方式来获取 Nacos。
从 Github 上下载源码方式
git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
ls -al distribution/target/
// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin
下载编译后压缩包方式
您可以从 最新稳定版本 下载 nacos-server-$version.zip 包。
unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
cd nacos/bin
3.启动服务器
Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式):
sh startup.sh -m standalone
如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

bash startup.sh -m standalone
Windows
启动命令:
cmd startup.cmd
或者双击startup.cmd运行文件。
4.服务注册&发现和配置管理
服务注册
curl -X POST ‘http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080’
服务发现
curl -X GET ‘http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName’
发布配置
curl -X POST “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld”
获取配置
curl -X GET “http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test”
5.关闭服务器
Linux/Unix/Mac
sh shutdown.sh
Windows
cmd shutdown.cmd
或者双击shutdown.cmd运行文件。

DOCKER uick Start

Run the following command:

Clone project

git clone --depth 1 https://github.com/nacos-group/nacos-docker.git
cd nacos-docker

Standalone Derby

docker-compose -f example/standalone-derby.yaml up

Standalone Mysql

docker-compose -f example/standalone-mysql.yaml up

Cluster

docker-compose -f example/cluster-hostname.yaml up 

Service registration

curl -X PUT 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'

Service discovery

  curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instances?serviceName=nacos.naming.serviceName'

Publish config

curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=helloWorld"

Get config

  curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"

Open the Nacos console in your browser

link:http://127.0.0.1:8848/nacos/ 默认账号密码都是nacos

Common property configuration

name description option
MODE cluster/standalone cluster/standalone default cluster
NACOS_SERVERS nacos cluster address eg. ip1:port1 ip2:port2 ip3:port3
PREFER_HOST_MODE Whether hostname are supported hostname/ip default ip
NACOS_SERVER_PORT nacos server port default 8848
NACOS_SERVER_IP custom nacos server ip when network was mutil-network
SPRING_DATASOURCE_PLATFORM standalone support mysql mysql / empty default empty
MYSQL_SERVICE_HOST mysql host
MYSQL_SERVICE_PORT mysql database port default : 3306
MYSQL_SERVICE_DB_NAME mysql database name
MYSQL_SERVICE_USER username of database
MYSQL_SERVICE_PASSWORD password of database
MYSQL_MASTER_SERVICE_HOST The latest version of the image removes this attribute, using MYSQL_SERVICE_HOST
MYSQL_MASTER_SERVICE_PORT The latest version of the image removes this attribute, using MYSQL_SERVICE_PORT default : 3306
MYSQL_MASTER_SERVICE_DB_NAME The latest version of the image removes this attribute, using MYSQL_SERVICE_DB_NAME
MYSQL_MASTER_SERVICE_USER The latest version of the image removes this attribute, using MYSQL_SERVICE_USER
MYSQL_MASTER_SERVICE_PASSWORD The latest version of the image removes this attribute, using MYSQL_SERVICE_PASSWORD
MYSQL_SLAVE_SERVICE_HOST The latest version of the image removes this attribute
MYSQL_SLAVE_SERVICE_PORT The latest version of the image removes this attribute default :3306
MYSQL_DATABASE_NUM It indicates the number of database default :1
JVM_XMS -Xms default :2g
JVM_XMX -Xmx default :2g
JVM_XMN -Xmn default :1g
JVM_MS -XX:MetaspaceSize default :128m
JVM_MMS -XX:MaxMetaspaceSize default :320m
NACOS_DEBUG enable remote debug y/n default :n
TOMCAT_ACCESSLOG_ENABLED server.tomcat.accesslog.enabled default :false
NACOS_AUTH_SYSTEM_TYPE The auth system to use, currently only ‘nacos’ is supported default :nacos
NACOS_AUTH_ENABLE If turn on auth system default :false
NACOS_AUTH_TOKEN_EXPIRE_SECONDS The token expiration in seconds default :18000
NACOS_AUTH_TOKEN The default token default :SecretKey012345678901234567890123456789012345678901234567890123456789
NACOS_AUTH_CACHE_ENABLE Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay. default : false

集成

<!--阿里依赖管理-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <!--<version>${latest.version}</version>-->
        </dependency>

spring.application.name=nacos
spring.cloud.nacos.discovery.server-addr=102.168.88.127:8848

在 Nacos Spring Cloud 中,dataId 的完整格式如下:
${prefix}-${spring.profile.active}.${file-extension}

    prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。
    spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profile.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
    file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.88.127:8848
      config:
        server-addr: 192.168.88.127:8848
        #namespace: example.properties # Data Id
        file-extension: yml # yml or properties

Nexus Maven库

# 赋予权限,不然启动会报错,无操作权限
chmod 777 nexus-data
docker run -d -p 8081:8081 --name nexus -v /srv/nexus-data:/nexus-data --restart=always sonatype/nexus3
# 进入镜像
docker exec -it nexus bash
# 查看密码,路径在登录框会提示,然后复制即可,登陆成功后会让你修改密码
cat /nexus-data/admin-password

二、Nexus仓库
1、仓库类型
Nexus有四种仓库和四种仓库类型
a、仓库
仓库名 描述
maven-central maven中央库,默认从https://repo1.maven.org/maven2/拉取jar
maven-releases 私库发行版jar
maven-snapshots 私库快照(调试版本)jar
maven-public 仓库分组,把上面三个仓库组合在一起对外提供服务,在本地maven基础配置settings.xml中使用
b、类型
类型 描述
group(仓库组类型) 用于方便开发人员自己设定的仓库
hosted(宿主类型) 内部项目的发布仓库(内部开发人员,发布上去存放的仓库)
proxy(代理类型) 从远程中央仓库中寻找数据的仓库(可以点击对应的仓库的Configuration页签下Remote Storage Location属性的值即被代理的远程仓库的路径)
virtual(虚拟类型) 虚拟仓库(这个基本用不到,重点关注上面三个仓库的使用)

2、拉取jar包流程
Maven可直接从宿主仓库下载构件,也可以从代理仓库下载构件,而代理仓库间接的从远程仓库下载并缓存构件,为了方便,Maven可以从仓库组下载构件,而仓库组并没有实际的内容(下图中用虚线表示,它会转向包含的宿主仓库或者代理仓库获得实际构件的内容)

3、创建仓库
进过上面的讲解,我们对仓库已经有了了解,接下来我们进行创建仓库,分为是代理仓库(proxy)、宿主仓库(hosted)、仓库组(group),点击主页上面的小螺丝然后在选择Repositories进入仓库管理列表,然后就可以开始创建我们的仓库啦,选择仓库类型的时候一定要选择maven2

第一种是在项目的pom.xml中进行更改,让单个项目使用nexus仓库;

代理中央仓库
只要在PMO文件中配置私服的地址即可,配置如下:
<repositories>
        <repository>
            <id>maven-central</id>
            <name>maven-central</name>
            <url>http://maven:8081/repository/maven-public/</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <releases>
                <enabled>true</enabled>
            </releases>
        </repository>
    </repositories>
maven配置setting文件
Snapshot包的管理
1)修改Maven的settings.xml文件,加入认证机制
<servers>
    <server>
      <id>nexus</id><!--对应项目pom文件中设置的-->
      <username>admin</username>
      <password>admin123</password>
    </server>
</servers>
修改工程的Pom文件 要配置snapshot仓库
    <distributionManagement>
        <repository>
            <!--ID可以随便写,但是要与maven的setting文件中一致-->
            <id>releases</id>
             <name>Nexus Repository</name>
            <!--指向仓库类型为hosted(宿主仓库)的储存类型为Release的仓库---->
            <url>http://你nexus仓库的IP:8081/repository/me-release/</url>
        </repository>
        <snapshotRepository>
            <id>nexus</id>
            <name>Nexus Snapshot</name>
            <url>http://192.168.1.14:8081/repository/maven-snapshots/</url>
        </snapshotRepository>
        <site>
            <id>nexus</id>
            <name>Nexus Sites</name>
            <url>dav:http://192.168.1.14:8081/repository/maven-snapshots/</url>
        </site>
    </distributionManagement>

一种是通过修改maven的配置文件settings.xml进行更改,让所有项目都使用nexus仓库。

Maven 的配置文件名称为:setting.xml。它被存放在两个地方:
1)/usr/local/maven/conf/settings.xml #安装的目录;
2)~/.m2/settings.xml #用户的家目录;
如果两者都存在,他们的内容将被合并,并且用户范围的settings.xml优先。
关于settings.xml文件常用的的配置修改如下:
1)修改本地仓库存储路径,默认值是~/.m2/repository 可在settings.xml中的localrepository修改成自己需要的目录;
2)如果构建服务器因为网络故障或者安全问题不能与远程仓库相连,需要离线模式下,设置offline属性,设置为true,默认为false;
3)修改中央仓库服务器,修改配置文件中便签,添加或修改镜像地址;
4)设置代理地址,修改配置文件中proxy标签,定义代理服务器,实现maven的代理。

拉取jar的私服仓库地址只要写我们的仓库组就ok,因为在创建这个组的时候,里面已经包含了其它三个仓库
settings.xml文件
在maven的settings文件中找到mirrors,加上我们组仓库的mirror,url填写我们创建的组地址即可,id、name可以随便填写

 <!-- 配置Maven服务器的账号信息,上传需要用到 -->
    <server>
        <id>maven-releases</id>
        <username>developer</username>
        <password>developer</password>
    </server>
    <server>
        <id>maven-snapshots</id>
        <username>developer</username>
        <password>developer</password>
    </server>
    <server>
        <id>maven-public</id>
        <username>developer</username>
        <password>developer</password>
    </server>
 <!-- 使用Mirror配置节可以强制所有包请求都会被转向内网Nexus服务器的地址 -->
<mirrors>
    <mirror>
        <id>maven-public</id>
        <name>myself nexus repository</name>
        <url>http://maven:8081/repository/maven-public/</url>
        <!--里是要替代的仓库的id。代理原有仓库,如果填写*表示替换所有仓库-->
        <mirrorOf>central</mirrorOf>
    </mirror>
     <mirror>
      <id>maven-releases</id>
      <name>myself nexus maven-releases</name>
      <url>http://maven:8081/repository/maven-releases/</url>
      <!--里是要替代的仓库的id。代理原有仓库,如果填写*表示替换所有仓库-->
      <mirrorOf>central</mirrorOf>
    </mirror>
    <mirror>
      <id>maven-snapshots</id>
      <name>myself nexus maven-snapshots</name>
      <url>http://maven:8081/repository/maven-snapshots/</url>
      <!--里是要替代的仓库的id。代理原有仓库,如果填写*表示替换所有仓库-->
      <mirrorOf>central</mirrorOf>
    </mirror>
  </mirrors>
   <!-- 这个配置决定了我们的Maven服务器开启snapshot配置,否则不能下载SNAPSHOTS的相关资源 -->
</profiles>
 <profile>
       <id>myconf</id>
      <repositories>
         <repository>
           <id>nexus</id>
           <url>http://maven:8081/repository/maven-public/</url>
           <releases>
             <enable>true</enable>
           </releases>
           <snapshots>
             <enable>true</enable>
             <updatePolicy>always</updatePolicy>
           </snapshots>
        </repository>
       </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>nexus</id>
          <url>http://maven:8081/repository/maven-public/</url>
           <releases>
            <enable>true</enable>
          </releases>
          <snapshots>
             <enable>true</enable>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
     </profile>
  </profiles>       需在该标签以上进行添加!
  <activeProfiles>
    <activeProfile>myconf</activeProfile>    这里的值一定要和上面profile的ID对应,才可以激活
  </activeProfiles>
</settings>          将 <activeProfiles>字段写在settings字段上面
需要发布jar资源到团队内部镜像服务器的项目的pom.xml配置<distributionManagement>增加snapshot的支持,
 <distributionManagement>
        <repository>
            <id>maven-releases</id>
            <name>Nexus Release Repository</name>
            <url>http://maven:8081/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>maven-snapshots</id>
            <name>Nexus Snapshot Repository</name>
            <url>http://maven:8081/repository/maven-snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

Nexus 启用上传功能
  团队有了私有的镜像服务器以后,团队内部代码的依赖也就不再需要源码依赖了,大家可以通过发布不同版本的jar到nexus镜像上来供调用者直接通过Maven下载使用,这样不同研发人员直接的依赖也就没有那么强了,大家可以基于已经发布的版本进行各自的开发。
  那么如何发布个人的jar资源到团队内部镜像上呢?
  1. 在Nexus 中创建一个developer的角色,拥有的权利为【nx-repository-view-maven2--edit】和【nx-repository-view-maven2--add】权利,如果该角色将来可能还有nuget,npm相关上传权利,则将其权利改为【nx-repository-view--edit】和【nx-repository-view--add】权利。
  2. 创建用户,用户拥有的角色为【nx-anonymous】和刚创建的【developer】角色。其中nx-anonymous角色是nexus默认自带的角色。

上传到私仓库 mvn clean deploy -U

异常处理

*UNKNOWN com.sonatype.nexus.plugins.outreach.internal.outreach.SonatypeOutreach – Could not download page bundle
org.apache.http.conn.HttpHostConnectException: Connect to sonatype-download.global.ssl.fastly.net:443 [sonatype-download.global.ssl.fastly.net/69.171.245.49] failed: 连接超时
打开【System】–》【Capabilities】,将【Outreach:Management】禁用即可。
mvn deploy

Pinpoint 链路监控

链路监控 Pinpoint

https://github.com/naver/pinpoint
安装服务
https://github.com/naver/pinpoint-docker

https://github.com/naver/pinpoint/releases
下载 pinpoint-agent-2.0.2.tar.gz
修改配制文件ponpoint.config
profiler.collector.iP=XX.XX.XXX.XXX #服务器地址
profiler.sampling.rate = 1 采样率1/N,1为100%全部采,20=5%
profiler.applicationservertype=TOMCAT 改SPRING_BOOT 采样服务器类型
查找修改SPRING_BOOT配制中的
profiler.sprintboot.bootstrap.main,增加要监控的main()函数类名
com.xx.xx

配制应用启动参数,指明使用代理
running the application:

-javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar
Additionally, Pinpoint Agent requires 2 command-line arguments in order to identify itself in the distributed system:
-Dpinpoint.agentId – uniquely identifies the application instance in which the agent is running on
-Dpinpoint.applicationName – groups a number of identical application instances as a single service

与日志相结合,利用 Transation 与ELK关联

docker-elk

github源码
Bringing up the stack
Clone this repository onto the Docker host that will run the stack, then start services locally using Docker Compose:
$ docker-compose up

5000: Logstash TCP input
9200: Elasticsearch HTTP user:elastic password:changeme
9300: Elasticsearch TCP transport 集群通信保持心跳
5601: Kibana      user:elastic password:changeme

LogStash 离散的日志收集,处理,过滤,格式转换
ElasticSearch 搜索引擎,进行索引,方便检索
Kibana 展示数据

springboot集成logbacku将日志输出到logstash

<!-- https://mvnrepository.com/artifact/net.logstash.logback/logstash-logback-encoder -->
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>6.3</version>
</dependency>

grok表达式

logstash.config
filter{
    grok{
        match => {
            "message" => "%{TIMESTAPM_ISO8601:logTime} %{GREEDYDATA:logThread} %{LOGLEVEL:logLevel} %{GREEDYDATA:loggerClass} - %{GREEDYDATA:logContent}"
        }
    }
}

在ELK前使用消息队列提高可用性,可分享性,如Kafka
配制LogStash从kafka接收
配制springboot项目发送到kafka

<!-- https://mvnrepository.com/artifact/com.github.danielwegener/logback-kafka-appender -->
<dependency>
    <groupId>com.github.danielwegener</groupId>
    <artifactId>logback-kafka-appender</artifactId>
    <version>0.2.0-RC2</version>
</dependency>
建立日志配制文件logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<configuration>

    <!--将日志发送到LOGSTASH-->
   <!-- <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashAccessTcpSocketAppender">
        <destination>localhost:5000</destination>-->
        <!--整个日志信息转为一个JSON发送-->
       <!-- <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>-->
        <!--自定义一个发送格式-->
       <!-- <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>-->

    <!--将日志发送到kafka-->
    <appender name="KAFKA" class="com.github.danielwegener.logback.kafka.KafkaAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <topic>test</topic>
        <keyingStrategy class="com.github.danielwegener.logback.kafka.keying.NoKeyKeyingStrategy"/>
        <deliveryStrategy class="com.github.danielwegener.logback.kafka.delivery.AsynchronousDeliveryStrategy"/>
        <producerConfig>bootstrap.servers=192.168.88.108:9092</producerConfig>
        <appender-ref ref="CONSOLE"/>
    </appender>

    <include resource="org/springframework/boot/logging/logback/base.xml"/>

    <root level="INFO">
        <!--<appender-ref ref="LOGSTASH"/>-->
        <appender-ref ref="KAFKA"/>
        <appender-ref ref="CONSOLE"/>
    </root>

</configuration>