下载地址​​​​​​​Downloads | Apache SkyWalking

SkyWalking APM 9.2.0

Java Agent 8.12.0

linux搭建skywalking

0.安装jdk,配置环境变量

1.安装es,elasticsearch.service,修改内存限制LimitMEMLOCK=infinity # 增加配置

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.15.2-x86_64.rpm

2.使用es存储,服务启动默认4g内存

vim /etc/elasticsearch/jvm.options

-Xms1g
-Xmx1g

3.重新加载启动脚本并启动并加入开机自启

systemctl daemon-reload && systemctl start elasticsearch && systemctl enable elasticsearch

systemctl status elasticsearch查看运行状态

systemctl stop elasticsearch停止es

4.skywalking默认采用h2存储

5.curl 127.0.0.1:9200查看cluster.name

cluster.name: cghes与SW_NAMESPACE对应,启动oapService.sh成功后占用 11800,12800端口(netstat -lntp查看) 

               

1. 链路追踪框架对比

项目CatZipkinSkyWalking
调用链可视化
聚合报表非常丰富较丰富
服务依赖图简单简单
埋点方式侵入式侵入式非侵入,字节码增强
VM监控指标
支持语言java/.net丰富java/.net/Nodejs/php/go
存储机制mysql(报表),本地文件/HDFS(调用链)内存,es,mysql等H2,es
社区支持主要国内国外主流Apache支持
使用案例美团,携程,陆金所京东,阿里定制后不开源华为,小米,当当,微众银行
APM
是否支持webflux

2.微服务接入SkyWalking,每一个微服务启动加入agent,针对不同的服务开启探针配置agent.conf收集数据的颗粒度

# skywalking-agent.jar的磁盘路径
-javaagent:所在路径 jar 
# 在skywalking上显示的服务名
-DSW_AGENT_NAME=dev-third

3.探针配置agent.conf

agent/config/agent.config中支持的属性列表

属性名描述默认值
agent.namespace命名空间,用于隔离跨进程传播的header。如果进行了配置,header将为HeaderName:Namespace.未设置
collector.backend_service接收skywalking trace数据的后端地址127.0.0.1:11800
plugin.mysql.trace_sql_parameters如果设置为 true, SQL 查询 (典型的是 java.sql.PreparedStatement) 的参数也会被采集.false
plugin.tomcat.collect_http_params这个配置项控制Tomcat插件是否应该收集请求的参数. 同样,在概要追踪中隐式激活.false
plugin.springmvc.collect_http_params这个配置项控制SpringMVC插件是否应该收集请求的参数, 当您的Spring应用程序基于Tomcat时, 只需要设置 plugin.tomcat.collect_http_params 或 plugin.springmvc.collect_http_params 之一. 同样,在概要追踪中隐式激活.false
plugin.http.http_params_length_threshold当启用 COLLECT_HTTP_PARAMS时,要保留多少字符并将其发送到OAP后端,请使用负值来保留和发送完整的参数. 添加这个配置项是为了提高性能.1024
plugin.jedis.trace_redis_parameters如果设置为 true,redis参数将被采集false
plugin.mongodb.trace_param如果为true,记录所有访问MongoDB的参数信息。默认为false,表示仅记录操作名,不记录参数信息。false
plugin.postgresql.trace_sql_parameters如果设置为true,将收集sql的参数(通常是 java.sql.PreparedStatement).false
plugin.elasticsearch.trace_dsl如果为true,记录所有访问ElasticSearch的DSL信息。默认为falsefalse
plugin.springmvc.use_qualified_name_as_endpoint_name如果为true,endpoint的name为方法的全限定名,而不是请求的URL。默认为false。false
plugin.solrj.trace_statement如果为 true, 追踪 Solr 查询请求中的所有查询参数(包括 deleteByIds 和 deleteByQuery) 默认为 false.false
plugin.feign.collect_request_body如果为 true, fegin调用请求体将打印false

4.追踪Gateway
Spring Cloud Gateway 是基于 WebFlux 实现,必须搭配上apm-spring-cloud-gateway-2.1.x-plugin 和 apm-spring-webflux-x.x-plugin 两个插件

将agent/optional-plugins下的两个插件 复制到 agent/plugins目录下
5.请求参数上报

pom.xml依赖

<dependency>
    <groupId>org.apache.skywalking</groupId>
    <artifactId>apm-toolkit-trace</artifactId>
</dependency>

common工程下新建请求参数filter类extend HttpFilter,微服务工程启动类加扫包

import com.alibaba.nacos.shaded.com.google.common.collect.ImmutableSet;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * skywalking 请求参数封装,通过ActiveSpan,输出到skywalking,如需打印,启动类加入扫包 com.***.***.common.skywalking
 */
@Slf4j
@Component
public class SkyWalkingReqParamFilter extends HttpFilter {
    private static final ImmutableSet<String> IGNORED_HEADERS;
    static {
        Set<String> ignoredHeaders = ImmutableSet.of(
                "Content-Type",
                "User-Agent",
                "Accept",
                "Cache-Control",
                "Postman-Token",
                "Host",
                "Accept-Encoding",
                "Connection",
                "Content-Length")
                .stream()
                .map(String::toUpperCase)
                .collect(Collectors.toSet());
        IGNORED_HEADERS = ImmutableSet.copyOf(ignoredHeaders);
    }

    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
        try {
            filterChain.doFilter(requestWrapper, responseWrapper);
        } finally {
            try {
                //构造请求的方法&URL&参数
                StringBuilder sb = new StringBuilder("curl")
                        .append(" -X ").append(request.getMethod())
                        .append(" ").append(request.getRequestURL().toString());
                if (StringUtils.hasLength(request.getQueryString())) {
                    sb.append("?").append(request.getQueryString());
                }
                //构造header
                Enumeration<String> headerNames = request.getHeaderNames();
                while (headerNames.hasMoreElements()) {
                    String headerName = headerNames.nextElement();
                    if (!IGNORED_HEADERS.contains(headerName.toUpperCase())) {
                        sb.append(" -H '").append(headerName).append(": ").append(request.getHeader(headerName)).append("'");
                    }
                }
                //获取body
                String body = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
                if (StringUtils.hasLength(body)) {
                    sb.append(" -d '").append(body).append("'");
                }
                //输出到input
                ActiveSpan.tag("input", sb.toString());
                //获取返回值body
                String responseBody = new String(responseWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
                //输出到output
                ActiveSpan.tag("output", responseBody);
            } catch (Exception e) {
                log.warn("fail to build http log", e);
            } finally {
                responseWrapper.copyBodyToResponse();
            }
        }
    }
}

6.skywalking整合logback

pom依赖

     <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
        </dependency>

 logback-spring.xml,区分环境

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
    <property scope="context" name="pattern"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS}[%X{traceId},%X{spanId}][${spring.application.name}][%c%L]-%-5level [%thread] %msg%n"/>
    <property scope="context" name="log.home" value="${user.home}/logs/${spring.application.name}"/>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>${pattern}</Pattern>
        </layout>
    </appender>


    <appender name="DEFAULT-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <file>${log.home}/default.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.home}/%d{yyyy-MM-dd}/default-%i.log.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
            <totalSizeCap>5GB</totalSizeCap>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 文件达到 最大128MB时会被压缩和切割 -->
                <maxFileSize>128 MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>${pattern}</Pattern>
        </layout>
    </appender>

    <appender name="ERROR-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <file>${log.home}/error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.home}/error.log.%d{yyyy-MM-dd}</FileNamePattern>
            <MaxHistory>7</MaxHistory>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>${pattern}</Pattern>
        </layout>
    </appender>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 日志的格式化-->
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <Pattern>
                    -%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint}%clr(${LOG_LEVEL_PATTERN:-%5p})
                    %clr(${PID:- }){magenta} [%tid] %clr(---){faint}%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan}
                    %clr(:){faint}%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
                </Pattern>

            </layout>

        </encoder>
    </appender>

    <!-- grpc方式将traceId推送至skywalking-->
    <appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
                <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
            </layout>
        </encoder>
    </appender>


    <springProfile name="dev">
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
        </root>
    </springProfile>

    <springProfile name="test,uat">
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="DEFAULT-APPENDER"/>
            <appender-ref ref="ERROR-APPENDER"/>
        </root>
    </springProfile>

    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="grpc-log"/>
            <appender-ref ref="DEFAULT-APPENDER"/>
            <appender-ref ref="ERROR-APPENDER"/>
        </root>
    </springProfile>
</configuration>

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐