循序渐进 · 教学 · 函数(十一)

函数里的日志与埋点

从函数里主动发出日志和 span,才能在生产环境监控和排查。这篇讲支持哪些遥测类型、怎么写、以及日志的最佳实践。

全部目录 ← 上一篇 函数里的日志与埋点 下一篇 →
本文来源 · Source 内容整理自 Palantir Foundry 官方文档:
https://www.palantir.com/docs/foundry/functions/instrumentation-telemetry/
原始标题:Function management > Instrumentation and telemetry

先记住这几条

① 两类遥测:日志与 span
日志记事件,span 记录一段执行的耗时与调用关系。
② 目的是生产排障
没有埋点,线上出问题只能盲猜。
③ 日志有最佳实践
乱打日志会产生噪音甚至性能问题,要讲方法。
0

写在前面

你可以从函数里主动发出某些类型的遥测数据,用来监控和排查生产环境的工作流。

想了解如何查看函数发出的遥测数据,参见本体与 AIP 可观测性文档

1

支持的遥测类型

支持的遥测类型

要点:Logs 与 Spans 两类,先看各自适用场景。

下表概览了每种函数语言支持的遥测类型。无论哪种函数,平台都会自动创建一个覆盖函数整个执行时长的 span,以及一条请求日志。

语言日志Span指标
TypeScript v1支持仅平台预定义的 span[1]仅平台预定义的指标[2]
TypeScript v2支持支持[3]仅平台预定义的指标[2]
Python支持支持[3]仅平台预定义的指标[2]

[1] TypeScript v1 函数里平台预定义的 span 包括对象加载、查询执行这类操作。

[2] Foundry 会为所有类型的函数记录总执行时长。

[3] TypeScript v2 与 Python 函数会自动为所有出向网络请求打点,此外你也可以自己添加自定义 span。

Logs

你可以从函数里发出自定义日志,并在事后回看。下面的例子演示了 TypeScript v1、TypeScript v2 和 Python 函数分别怎么打日志。

在 TypeScript v2 函数里,Foundry 会帮你初始化 OpenTelemetry SDK 的全局 logger provider,你可以从它那里取到一个 logger。如果你想用第三方日志库,必须把它们配置成通过从全局 logger provider 取到的 logger 来输出日志。

export class MyFunctions {
    @Function()
    public myFunction(name: string): string {
        console.log(`This is a custom log line, ${name}.`);
        return `Hello, ${name}!`;
    }
}
import { logs } from "@opentelemetry/api-logs";

const logger = logs.getLogger("my-function");

export default function myFunction(name: string): string {
    logger.emit({
        body: "This is a custom log line.",
        attributes: {
            name
        },
    });

    // 也可以直接用全局的 console 对象
    console.log(`This is a custom log line, ${name}.`);

    return `Hello, ${name}!`;
}
import logging

from functions.api import function

logger = logging.getLogger(__name__)

@function
def my_function(name: str) -> str:
    logger.info("This is a custom log line.")
    return f"Hello, {name}!"

Logging best practices

打日志请遵循下面这些做法:

  • 选对日志级别: 正常操作用 INFO,可恢复的问题用 WARN,失败用 ERROR,详细诊断信息用 DEBUG
  • 带上相关上下文: 加上标识符、数量、操作细节,便于理解执行过程。
  • 不要打敏感数据: 不要记录凭据、可能含敏感信息的完整 API 响应,或其他涉密内容。

关于如何写好日志、查看服务日志、按级别过滤,参见服务日志与调试

Spans

你也可以在 TypeScript v2 和 Python 函数里创建自定义 span,用来跟踪某个具体操作耗时多久。下面的例子演示了如何创建自定义 span。

在 TypeScript v2 和 Python 函数里,Foundry 会帮你初始化 OpenTelemetry SDK 的全局 tracer provider,你可以从它那里取到一个 tracer。如果你想用第三方链路追踪库,必须把它们配置成通过从全局 tracer provider 取到的 tracer 来输出追踪数据。

import { trace } from "@opentelemetry/api";
import { Integer } from "@osdk/functions";

const tracer = trace.getTracer("my-function");

export default function sqrt(n: Integer): Integer {
    const sqrt = tracer.startActiveSpan("my-custom-span", (span) => {
        try {
            return Math.sqrt(n);
        } finally {
            span.end();
        }
    });

    return sqrt;
}
import math

from functions.api import function

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

@function
def sqrt(n: int) -> int:
    with tracer.start_as_current_span("my-custom-span"):
        return math.sqrt(n)

延伸阅读 · 相关页面

按主题横向跳转,不必顺着目录一篇篇读。