使用 Golang 语言编写一个简易的 HTTP 接口,用于接收 Fastly CDN 的实时日志。

这次的文章同样也是在实现后拖延一小段时间再撰写本编水文的。

得益于 EdgeOne CDN 的 HTTP 实时日志接口这一轮子的重复造车成功,现在也可以研究实现将 Fastly CDN 的实时日志推送到 HTTPS 端点了。

之前我在使用 Fastly CDN 时没第一时间选择 HTTPS 方式推送日志,全赖于我当时只想到使用 PHP 语言编写接口,因此出于担心性能不足以支撑“庞大的”推送请求的原因,转而使用 SFTP 这一方式(详情可以参考本站前面所些的文章。)推送并接收存储实时请求日志。

当前 Fastly CDN 支持以下日志端点:

  1. Amazon Kinesis Data Streams
  2. Amazon S3
  3. Apache Kafka
  4. Datadog
  5. Elasticsearch
  6. FTP
  7. Google BigQuery
  8. Google Cloud Storage
  9. Grafana Cloud Logs
  10. HTTPS
  11. Google Cloud Pub/Sub
  12. Heroku Logplex
  13. Honeycomb
  14. LogDNA (via Syslog)
  15. Loggly
  16. Logshuttle
  17. Microsoft Azure Blob Storage
  18. New Relic Logs
  19. New Relic OTLP
  20. Openstack
  21. Papertrail
  22. Rackspace Cloud Files
  23. Scalyr
  24. SFTP
  25. Spaces by DigitalOcean
  26. Splunk
  27. Sumologic
  28. Syslog
  29. ……

根据需求本次选择 HTTPS 的方式发送日志。

使用示例

启动 WEB 接口

  1. 编译后的fastly-realtime-logs-for-golang文件传至服务器。
  2. 编辑.env文件:
    TIME_ZONE=Asia/Shanghai # 时区
    
    HTTPS_LISTEN=:34443 # HTTPS 端口
    CA_FILE="cert/ca.cer" # SSL CA 证书文件路径
    CERT_FILE="cert/server.pem" # HTTPS 证书文件路径
    KEY_FILE="cert/server.key" # HTTPS 密钥文件路径
    
    LOG_ROOT=./logs     # 根目录 例如:/data/logs/json_logs
    RECEIVE_PATH=/receive # 接收URI,不能为“/”
    WELL_KNOWN_CHALLENGE="sha256sum \n SERVICEID" // SHA256 SERVICEID
    
  3. 运行:
    nohup ./fastly-realtime-logs-for-golang &
    
  4. 验证:
    netstat -antupl|grep fastly-realt
    

同样的暂时使用nohup实现后台运行。

其中WELL_KNOWN_CHALLENGE参数是用于所有权认证使用的,其值为对应域名的 SERVICEID 的 SHA256 哈希值。若是需要一个接口对应多个不同的 SERVICE ,暂时可以通过使用\n解决多个域名的共用问题。

在 Fastly CDN 中配置推送信息

  1. 登陆 Fastly 控制台,并进入对应的域名配置。
  2. 点击【Edit configuration】,在下拉中选择【Clone version xx (active) to edit】复制一份新的配置文件进行修改。
  3. 在左边栏选择【Logging】,配置日志端点。
  4. 如果有配置过日志任务需要点击【Create endpoint】,没有的情况下直接选择推送的类型即可。
  5. 选择【HTTPS】协议推送,点击【Create endpoint】创建并进行配置。
  6. 配置 HTTPS 端点任务:
    1. Name,一个容易辨别的名字,例如【logs2https】。
    2. Placement,选择默认的【Format Version Default】
    3. Log format,保留默认的即可,有其他需求再行修改。
      {
          "timestamp": "%{strftime(\{"%Y-%m-%dT%H:%M:%S%z"\}, time.start)}V",
          "client_ip": "%{req.http.Fastly-Client-IP}V",
          "geo_country": "%{client.geo.country_name}V",
          "geo_city": "%{client.geo.city}V",
          "host": "%{if(req.http.Fastly-Orig-Host, req.http.Fastly-Orig-Host, req.http.Host)}V",
          "url": "%{json.escape(req.url)}V",
          "request_method": "%{json.escape(req.method)}V",
          "request_protocol": "%{json.escape(req.proto)}V",
          "request_referer": "%{json.escape(req.http.referer)}V",
          "request_user_agent": "%{json.escape(req.http.User-Agent)}V",
          "response_state": "%{json.escape(fastly_info.state)}V",
          "response_status": %{resp.status}V,
          "response_reason": %{if(resp.response, "%22"+json.escape(resp.response)+"%22", "null")}V,
          "response_body_size": %{resp.body_bytes_written}V,
          "fastly_server": "%{json.escape(server.identity)}V",
          "fastly_is_edge": %{if(fastly.ff.visits_this_service == 0, "true", "false")}V
        }
      
    4. URL,接口地址:http(s)://ip:port(domain)/RECEIVE_PATH
    5. Maximum logs,默认:0
    6. Maximum bytes,默认:0
    7. 点击【Advanced options】展开配置高级设置:
      1. Content type,填写【application/json
      2. Custom header name,留空。用于区分域名存放日志的。
      3. Custom header value,留空。用于区分域名存放日志的。
      4. Method,选择【POST】
      5. JSON log entry format,选择【Disabled】
      6. Select a log line format,选择【Blank】
      7. Compression,可选【None】或者【Gzip】,其他压缩算法暂时未支持。建议选择【Gzip】。
      8. TLS hostname,自签 SSL 证书的【Common Names (CN)】
      9. TLS CA certificate,自签 SSL 证书的 CA 证书。
      10. TLS client certificate, SSL 双向认证证书。用于区分域名存放日志的。
      11. TLS client key, SSL 双向认证密钥。用于区分域名存放日志的。
  7. 点击【Create】保存上述的配置。
  8. 点击【Activate】,在出现的下拉中选择【Activate on Production】使其生效。
  9. 访问对应的域名后产生请求,稍后查看是否成功推送日志。

其本意是通过配置自定义请求头进行鉴权的,但是鉴于只能配置一个请求头且可以配置 SSL 双向认证,于是我将请求头用于共用时进行区分不同域名的用途。在配置X-Domain请求头时将用该请求头的值区分域名,否则就使用双向认证证书的Common Names (CN)区分对应的域名。

ChiuYut

2025年09月09日

发布者

ChiuYut

咦?我是谁?这是什么地方? Ya ha!我是ChiuYut!这里是我的小破站!