前言:
最近公司项目前端进行了重构,当然在这个时候有了一些新的需求,那就是在前端加入追踪,日志等相关记录,方便排查问题。刚好在9月份的时候grafana推了出他最新的前端事件追踪https://grafana.com/blog/2025/09/02/actionable-insights-into-the-end-user-experience-an-overview-of-grafana-cloud-frontend-observability-dashboards 这是官方的发布blog。刚好我需要这个东西,就搭建了一下。当然官方说的仅支持使用grafanacloud的用户。我想它能支持云原生,那我自建的就不支持了吗?抱着不信邪的态度,试了一下,结果没有失望,过程万分惆怅。
先发几张成功后的截图:
日志:

追踪
 、
、
指标

实操阶段:
前端准备:
引入faro-sdk,官方的由前端开发人员在代码里面引入。可以引入暴露指标的sdk,将指标提交到prometheus,通过grafana进行展示。
后端准备:
和前端没有什么区别,只是引入的sdk不一样,后端可以完全使用别的sdk来暴露指标,比如我们这边使用go,可以引成熟的开发熟悉的三方库。
运维准备:
1、安装prometheus(安装过程就是在多说了,前面文章有写)唯一注意的就是要加“--web.enable-remote-write-receiver” 这个参数。意思就是允许别的应用主动上传指标。默认是prometheus去拉数据。
2、安装alloy(如果使用grafana-cloud这个就不需要)这个刚刚出来没有多久的一个分析器。它的语法和配置都有点无法琢磨。作用是来接收faro的数据。并把数据解析为需要的格式。
先贴一个官方的安装教程地址:
https://grafana.com/docs/alloy/latest/set-up/install/binary/
2、1: 下载alloy
github项目地址:https://github.com/grafana/alloy/releases
也可以直接下载最新的版本:
wget https://github.com/grafana/alloy/releases/download/v1.11.3/alloy-1.11.3-1.amd64.rpm2、2:安装
dpkg -i alloy-1.11.3-1.amd64.rpm2、3查看状态
systemctl status alloy
● alloy.service - Grafana Alloy
     Loaded: loaded (/usr/lib/systemd/system/alloy.service; enabled; preset: en>
     Active: active (running) since Wed 2025-09-24 06:53:41 CST; 1 month 6 days>
   Main PID: 583991 (alloy-linux-amd)
      Tasks: 11 (limit: 18309)
     Memory: 134.5M (peak: 161.2M)
        CPU: 3h 23min 10.072s
     CGroup: /system.slice/alloy.service
             └─583991 /usr/local/alloy/alloy-linux-amd64 run --storage.path=/us>
Oct 30 16:34:11 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 16:34:29 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 16:38:32 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 16:50:32 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 16:53:44 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 16:53:44 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 16:53:44 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 16:59:48 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 17:01:03 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
Oct 30 17:03:33 iZt4n858ky4h79srauoa3kZ alloy-linux-amd64[583991]: ts=2025-10-3>
由于我安装的时候并没有安装包都是二进制文件,所有有些不一样,果然生态还在慢慢完善。
cat /usr/lib/systemd/system/alloy.service
[Unit]
Description=Grafana Alloy
After=network.target
[Service]
Type=simple
User=prometheus
WorkingDirectory=/usr/local/alloy
ExecStart=/usr/local/alloy/alloy-linux-amd64 run --storage.path=/usr/local/alloy/data /usr/local/alloy/config.alloy
Restart=on-failure
[Install]
WantedBy=multi-user.target这个是我当时安装自己写的systemctl管理文件,我不知道用rpm包安装的会不会有什么不一样。
2、4 配置文件config.alloy:(根据自己的环境更改)当时没有更多的说明,这个配置文件,我搞了一整天。哎!!!它这个格式有点让我头大。
注意,你们配置的时候必须将每行后面的注释删除掉,不然要报错。*-*!!!
// ==================== 基础配置部分 ====================
// 配置 Alloy 自身的日志行为
logging {
  level  = "info"           // 日志级别:info,生产环境推荐
  format = "logfmt"         // 日志格式:logfmt,便于解析
  write_to = [loki.process.alloy_logs.receiver]  // 将 Alloy 自身日志发送到 Loki 处理流水线
}
// 配置 Alloy 自身的分布式追踪
tracing {
  sampling_fraction = 0.1   // 追踪采样率 10%,生产环境推荐值,平衡性能与可观测性
  write_to = [otelcol.exporter.otlp.tempo.input]  // 追踪数据发送到 Tempo
}
// ==================== 1. Alloy 自身日志处理流水线 ====================
// 处理 Alloy 代理自身的日志
loki.process "alloy_logs" {
  forward_to = [loki.relabel.alloy_logs.receiver]  // 转发到重标签阶段
  // 添加固定标签,标识数据来源为 Alloy 代理
  stage.labels {
    values = { agent = "alloy" }
  }
}
// 对 Alloy 日志进行标签重写
loki.relabel "alloy_logs" {
  // 规则1:设置 job 标签为 "alloy",标识任务类型
  rule {
    target_label  = "job"
    replacement   = "alloy"
  }
  // 规则2:设置 instance 标签为主机名,标识实例
  rule {
    target_label  = "instance"
    replacement   = constants.hostname  // 使用 Alloy 常量获取主机名
  }
  forward_to = [loki.write.loki.receiver]  // 转发到 Loki 写入器
}
// ==================== 2. Loki 日志写入配置 ====================
// 配置如何将日志写入远程 Loki 服务
loki.write "loki" {
  endpoint {
    url = "http://192.168.0.63:3100/loki/api/v1/push"  // Loki 服务地址
    http_headers = { "X-Scope-OrgID" = ["bossvn"] }    // 多租户头部,指定组织ID
  }
}
// ==================== 3. Alloy 自身指标收集 ====================
// 导出 Alloy 自身的 Prometheus 指标
prometheus.exporter.self "alloy" {}
// 抓取 Alloy 自身指标并转发
prometheus.scrape "alloy" {
  targets    = prometheus.exporter.self.alloy.targets  // 抓取目标
  forward_to = [prometheus.remote_write.prometheus.receiver]  // 转发到远程写入
}
// ==================== 4. Prometheus 远程写入配置 ====================
// 配置指标数据远程写入到 Prometheus
prometheus.remote_write "prometheus" {
  endpoint {
    url = "http://192.168.0.63:9090/api/v1/write"  // Prometheus 远程写入地址
  }
}
// ==================== 5. Tempo 追踪数据导出配置 ====================
// 配置 OTLP 导出器,将追踪数据发送到 Tempo
otelcol.exporter.otlp "tempo" {
  client {
    endpoint = "192.168.0.63:4327"  // Tempo 服务的 OTLP 接收端点
    tls { insecure = true }          // 禁用 TLS 验证(开发环境)
  }
}
// ==================== 6. 后端应用 OTLP 接收器 ====================
// 为后端应用程序提供 OTLP 协议接收端点
otelcol.receiver.otlp "backend_apps" {
  // gRPC 协议接收配置
  grpc { 
    endpoint = "0.0.0.0:4317"  // 监听所有网卡的 4317 端口(gRPC)
  }
  // HTTP 协议接收配置  
  http { 
    endpoint = "0.0.0.0:4318"  // 监听所有网卡的 4318 端口(HTTP)
  }
  // 输出配置:定义接收到的数据如何路由
  output {
    // metrics = [prometheus.remote_write.prometheus.receiver]  // 指标路由(当前被注释)
    logs    = [otelcol.exporter.loki.app_logs.input]  // 日志路由到 Loki
    traces  = [otelcol.exporter.otlp.tempo.input]     // 追踪路由到 Tempo
  }
}
// ==================== 后端应用日志导出到 Loki ====================
// 将 OTLP 接收的日志转换为 Loki 格式并导出
otelcol.exporter.loki "app_logs" {
  forward_to = [loki.process.app_logs.receiver]  // 转发到应用日志处理流水线
}
// ==================== 7. 后端应用日志处理流水线 ====================
// 处理后端应用程序的日志数据
loki.process "app_logs" {
  forward_to = [loki.relabel.app_logs.receiver]  // 转发到重标签阶段
  
  // 第一阶段:logfmt 解析,从日志中提取结构化字段
  stage.logfmt {
    mapping = {
      "kind" = "",         // 提取 kind 字段(如 pod、service 等)
      "service_name" = "", // 提取服务名称字段
      "app_name" = "",     // 提取应用名称字段  
      "level" = "",        // 提取日志级别字段
      "message" = "",      // 提取日志消息字段
    }
  }
  
  // 第二阶段:将解析出的字段转换为标签
  stage.labels {
    values = {
      "kind" = "kind",          // 将 kind 字段值设为 kind 标签
      "service_name" = "service_name",  // 服务名作为标签
      "app" = "app_name",       // 应用名作为 app 标签
      "level" = "level",        // 日志级别作为标签
      "message" = "message",    // 消息内容作为标签
    }
  }
}
// 后端应用日志的标签重写
loki.relabel "app_logs" {
  // 规则1:设置 job 标签为 "backend_apps",标识后端应用任务
  rule {
    target_label  = "job"
    replacement   = "backend_apps"
  }
  // 规则2:设置 instance 标签为主机名
  rule {
    target_label  = "instance"
    replacement   = constants.hostname
  }
  forward_to = [loki.write.loki.receiver]  // 转发到 Loki 写入器
}
// ==================== 8. 前端应用日志处理流水线 ====================
// 处理前端应用程序的日志数据(与后端处理类似但独立)
loki.process "logs_process_client" {
  forward_to = [loki.write.loki.receiver]  // 直接转发到 Loki 写入器
  
  // logfmt 解析阶段
  stage.logfmt {
    mapping = {
      "kind" = "",         // 提取类型字段
      "service_name" = "", // 提取服务名字段
      "app_name" = "",     // 提取应用名字段
      "level" = "",        // 提取日志级别字段
      "message" = "",      // 提取消息字段
    }
  }
  
  // 标签转换阶段
  stage.labels {
    values = { 
      "kind" = "kind",          // 类型作为标签
      "service_name" = "service_name",  // 服务名作为标签
      "app" = "app_name",       // 应用名作为 app 标签
      "level" = "level",        // 日志级别作为标签
      "message" = "message",    // 消息作为标签
    }
  }
}
// ==================== 9. 前端应用监控接收器 ====================
// 专门接收 Web 前端应用的监控数据(Faro = Frontend Application Reporting and Observability)
faro.receiver "integrations_app_agent_receiver" {
  server {
    listen_address           = "0.0.0.0"        // 监听所有网络接口
    listen_port              = 9066             // 前端数据接收端口
    cors_allowed_origins     = ["*"]            // 允许所有域名跨域访问
    max_allowed_payload_size = "10MiB"          // 最大请求负载 10MB
    rate_limiting { rate = 100 }                // 速率限制:100 请求/秒
  }
  sourcemaps { }  // 支持 JavaScript sourcemap 解析,用于错误追踪
  
  // 输出配置:前端数据路由
  output {
    logs   = [loki.process.logs_process_client.receiver]  // 前端日志路由到处理流水线
    traces = [otelcol.exporter.otlp.tempo.input]          // 前端追踪路由到 Tempo
  }
}重启一下alloy
systemctl restart alloy && systemctl status alloy3、安装loki
还是先贴一个官方安装文档:https://grafana.com/docs/loki/latest/setup/install/install-from-source/
3、1:下载loki
github: https://github.com/grafana/loki
最新版本下载地址:
wget https://github.com/grafana/loki/releases/download/v3.5.7/loki-linux-amd64.zip3、2 安装
unzip loki-linux-amd64.zip
mv loki /usr/local/loki3、3 配置systemctl管理loki
创建loki.service,ubuntu20.04及以上目录是/usr/lib/systemd/system/ 如果ubuntu版本在18.及以下目录不一样。
[Unit]
Description=Loki Server Service daemon
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=Simple
ExecStart=/usr/local/loki/loki-linux-amd64 --config.file=/usr/local/loki/loki-local-config.yaml
Restart=on-failure
[Install]
WantedBy=multi-user.target3、4 创建配置文件:
vim loki-local-config.yaml
# ==================== 认证配置 ====================
# 启用认证机制(true: 需要认证, false: 无需认证)
auth_enabled: true
# ==================== 服务器配置 ====================
server:
  http_listen_port: 3100        # HTTP API 监听端口(Grafana 数据源连接端口)
  grpc_listen_port: 9096        # gRPC 监听端口(用于组件间通信)
  log_level: info               # 日志级别:debug, info, warn, error
  grpc_server_max_concurrent_streams: 1000  # gRPC 最大并发流数
# ==================== 通用配置 ====================
common:
  instance_addr: 192.168.0.63   # 实例地址,用于集群通信标识
  path_prefix: /usr/local/loki  # Loki 数据存储根路径
  
  # 存储配置 - 使用本地文件系统存储
  storage:
    filesystem:
      chunks_directory: /usr/local/loki/chunks                    # 日志块数据存储目录
      rules_directory: /usr/local/loki/rules/persistent_rules     # 持久化规则存储目录
  
  replication_factor: 1          # 数据复制因子(1=单机模式,3=集群模式)
  
  # 分布式环配置 - 使用内存存储(单机模式)
  ring:
    kvstore:
      store: inmemory           # 键值存储类型:inmemory(内存), consul, etcd
# ==================== 查询范围配置 ====================
query_range:
  # 查询结果缓存配置
  results_cache:
    cache:
      embedded_cache:
        enabled: true           # 启用嵌入式缓存
        max_size_mb: 100        # 缓存最大大小:100MB
# ==================== 限制配置 ====================
limits_config:
  metric_aggregation_enabled: true    # 启用指标聚合
  reject_old_samples_max_age: 168h    # 拒绝超过 168 小时(7天)的旧样本
  max_streams_per_user: 10000000      # 每个用户最大日志流数:1000万
  ingestion_rate_mb: 100              # 日志摄入速率限制:100 MB/秒
  max_query_length: 72h               # 最大查询时间范围:72小时
  reject_old_samples: true            # 启用拒绝旧样本检查
# ==================== 数据模式配置 ====================
schema_config:
  configs:
    - from: 2020-10-24          # 模式生效起始时间
      store: tsdb               # 存储引擎类型:tsdb(时间序列数据库)
      object_store: filesystem  # 对象存储类型:filesystem(文件系统)
      schema: v13               # 数据模式版本
      index:
        prefix: index_          # 索引文件前缀
        period: 24h             # 索引文件滚动周期:24小时
# ==================== 表管理配置 ====================
table_manager:
  retention_deletes_enabled: true    # 启用数据保留删除
  retention_period: 720h             # 数据保留周期:720小时(30天)
# ==================== 规则引擎配置 ====================
ruler:
  alertmanager_url: http://192.168.0.63:9093  # Alertmanager 服务地址
  rule_path: /usr/local/loki/rules/runtime_rules  # 运行时规则文件路径
  
  # 规则存储配置
  storage:
    type: local                  # 存储类型:local(本地文件系统)
    local:
      directory: /usr/local/loki/rules/persistent_rules  # 持久化规则目录
  
  # 规则引擎环配置
  ring:
    kvstore:
      store: inmemory           # 使用内存存储(单机模式)
# ==================== 查询前端配置 ====================
frontend:
  encoding: protobuf            # 查询结果编码格式:protobuf(二进制,性能更好)3、5 运行及状态查看:
systemctl enable loki --now && systemctl status loki
● loki.service - Loki Server Service daemon
     Loaded: loaded (/usr/lib/systemd/system/loki.service; enabled; preset: ena>
     Active: active (running) since Wed 2025-09-17 14:16:08 CST; 1 month 13 day>
   Main PID: 968 (loki-linux-amd6)
      Tasks: 11 (limit: 18309)
     Memory: 2.1G (peak: 2.5G)
        CPU: 4h 4min 10.869s
     CGroup: /system.slice/loki.service
             └─968 /usr/local/loki/loki-linux-amd64 --config.file=/usr/local/lo>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>
Oct 31 10:55:11 iZt4n858ky4h79srauoa3kZ loki-linux-amd64[968]: level=info ts=20>4、安装tempo
官方文档:https://grafana.com/docs/tempo/latest/
4、1 下载tempo
github地址:https://github.com/grafana/tempo
最新版本:
wget https://github.com/grafana/tempo/releases/download/v2.9.0/tempo_2.9.0_linux_amd64.tar.gz4、2 安装
tar -zxvf tempo_2.9.0_linux_amd64.tar.gz
mv tempo /usr/local/tempo4、3 配置systemctl管理tempo
vim tempo.service
[Unit]
Description=Grafana Tempo
After=network.target
[Service]
Type=simple
User=prometheus
WorkingDirectory=/usr/local/tempo
ExecStart=/usr/local/tempo/tempo -config.file /usr/local/tempo/tempo-local-config.yaml
Restart=on-failure
[Install]
WantedBy=multi-user.target4、4 创建配置文件:(我添加了注释)
vim tempo-local-config.yaml
# Tempo 服务器配置
server:
  # HTTP 服务监听端口
  # Grafana 通过此端口连接 Tempo 数据源
  # 提供查询API、健康检查、指标暴露等功能
  http_listen_port: 3200 
# 数据分发器配置 - 负责接收追踪数据
distributor:
  # 数据接收器配置
  receivers:
    # OTLP (OpenTelemetry Protocol) 接收器
    otlp:
      # 支持的协议类型
      protocols:
        # gRPC 协议配置
        grpc:
          # gRPC 服务监听端点
          # 0.0.0.0:4327 表示监听所有网卡的4327端口
          endpoint: "0.0.0.0:4327"
        # HTTP 协议配置  
        http:
          # HTTP 服务监听端点
          # 0.0.0.0:4328 表示监听所有网卡的4328端口
          endpoint: "0.0.0.0:4328"
# 数据处理器配置 - 负责处理和缓存追踪数据
ingester:
  # 最大块持续时间:5分钟
  # 控制内存中追踪数据块在写入存储前的保留时间
  # 缩短用于测试,生产环境建议 3h-6h
  max_block_duration: 5m
# 存储配置 - 定义数据持久化方式
storage:
  # 追踪数据存储配置
  trace:
    # 存储后端类型:local 表示使用本地文件系统
    backend: local
    # 本地存储配置
    local:
      # 追踪数据存储目录
      # 压缩后的追踪数据块存储在此路径
      path: /usr/local/tempo/data
    # 预写日志配置
    wal:
      # 预写日志存储目录
      # 用于确保数据写入的可靠性和崩溃恢复
      path: /usr/local/tempo/wal
    # 处理池配置
    pool:
      # 最大工作线程数:100
      # 控制并发处理追踪数据的线程数量
      max_workers: 100
      # 队列深度:10000  
      # 控制待处理任务的队列大小
      queue_depth: 100004、5 运行及状态查看
systemctl enable tempo --now && systemctl status tempo
● tempo.service - Grafana Tempo
     Loaded: loaded (/usr/lib/systemd/system/tempo.service; enabled; preset: enabled)
     Active: active (running) since Wed 2025-09-17 14:16:08 CST; 1 month 13 days ago
   Main PID: 1052 (tempo)
      Tasks: 11 (limit: 18309)
     Memory: 1.8G (peak: 4.7G)
        CPU: 4h 45min 45.647s
     CGroup: /system.slice/tempo.service
             └─1052 /usr/local/tempo/tempo -config.file /usr/local/tempo/tempo-local-config.yaml
Oct 31 11:26:11 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:26:11.012391087Z caller=retention.go:109 msg="deleting block" blockID=e60b54ae-1c87-4>
Oct 31 11:26:11 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:26:11.012630444Z caller=retention.go:109 msg="deleting block" blockID=f87ac83c-3fe6-4>
Oct 31 11:26:11 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:26:11.017200452Z caller=poller.go:304 msg="writing tenant index" tenant=single-tenant>
Oct 31 11:26:11 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:26:11.019804593Z caller=poller.go:251 msg="blocklist poll complete" seconds=0.0084414>
Oct 31 11:26:31 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:26:31.981631112Z caller=compactor.go:143 msg="starting compaction cycle" tenantID=sin>
Oct 31 11:26:31 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:26:31.981681273Z caller=compactor.go:156 msg="compaction cycle complete. No more bloc>
Oct 31 11:27:01 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:27:01.982166517Z caller=compactor.go:143 msg="starting compaction cycle" tenantID=sin>
Oct 31 11:27:01 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:27:01.98219917Z caller=compactor.go:156 msg="compaction cycle complete. No more block>
Oct 31 11:27:31 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:27:31.983059794Z caller=compactor.go:143 msg="starting compaction cycle" tenantID=sin>
Oct 31 11:27:31 iZt4n858ky4h79srauoa3kZ tempo[1052]: level=info ts=2025-10-31T03:27:31.983097064Z caller=compactor.go:156 msg="compaction cycle complete. No more bloc>到此准备工作就结束了。
grafana添加数据源:
关于grafana的安装教程,我前面文章有详细说明,这里就不在赘述。
添加loki数据源:(此处注意,如果在loki里开启了认证,这里需要添加租户验证-图2)


添加tempo数据源

到此配置全结束
关于grafana添加仪表盘官方有一些模版,但是关于faro的少得很,如果是使用cloud grafana就是自带的,而且全面。可是我没有。如果有的大兄弟们,希望能共享一下你们的仪表盘。我这边是自己创建的,很low。等有时间了再去优化它。
 
             
           
             
           
                        
评论区