开启链路追踪后,函数计算会自动记录请求在系统侧的耗时,包含冷启动耗时、Initializer函数的耗时和函数的执行时间等。如果您还需查看函数内业务侧的耗时,例如在函数内访问RDS、NAS等服务的耗时,则可通过本文提供的创建自定义Span步骤实现。

流程说明

您可以基于函数计算的链路创建自定义Span,将自定义的Span串联到函数计算的调用链中。函数计算的链路分析基于OpenTracing协议的Jaeger实现,提供以下两种方式创建自定义Span:

Jaeger和OpenTelemetry的详细信息,请分别参见JaegerOpenTelemetry

两种方式的流程说明如下:

  1. 在函数中引入Jaeger或OpenTelemetry依赖包。引入三方依赖的具体操作,请参见为函数安装第三方依赖
  2. 在函数中获取函数计算调用链的Span Context,根据函数计算的Span Context,创建自定义Span,在需要记录耗时的代码片段前后添加埋点。
  3. 完成后,您可以在函数详情页面的链路追踪页签或链路追踪控制台查看调用链信息。

使用Jaeger SDK

本文以Node.js运行时为例,介绍如何通过Serverless Devs创建自定义Span,创建并部署函数的步骤。

说明 您可以使用Serverless Devs安装依赖包,并打包部署到函数计算,您也可以通过其他方式打包并部署。Serverless Devs的更多信息,请参见什么是Serverless Devs
  1. 创建代码目录。
    mkdir jaeger-demo
  2. 初始化Node.js运行时模板。
    1. 执行以下命令,进入代码目录:
      cd jaeger-demo
    2. 在代码目录中执行以下命令,初始化Node.js 12的项目:
      s init devsapp/start-fc-event-nodejs12
      输出示例:
       Serverless Awesome: https://github.com/Serverless-Devs/package-awesome
      
       Please input your project name (init dir) (start-fc-event-nodejs12)
    3. 设置项目名称,然后按回车键。
      Serverless Devs已默认为您生成一个名为start-fc-event-nodejs12的项目,您可按需修改项目名称,本文以默认的项目名称为例。
      输出示例:
       Serverless Awesome: https://github.com/Serverless-Devs/package-awesome
      
       Please input your project name (init dir) start-fc-event-nodejs12
       file decompression completed
       please select credential alias (Use arrow keys)
      ❯ default
    4. 按需选择别名,然后按回车键。
    5. 按需选择是否部署该项目。
      由于本示例介绍的项目还需安装依赖,所以在是否立即部署该项目?(Y/n)后设置n选择不部署该项目。
  3. 执行以下命令,进行项目的代码目录:
    cd start-fc-event-nodejs12/code
  4. 在代码目录中,执行以下命令,初始化package.json文件。
    npm init -y
    输出示例:
    Wrote to /test/jjyy/start-fc-event-nodejs12/code/package.json:
    
    {
      "name": "code",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
  5. 执行以下命令,安装Jaeger依赖。
    npm i jaeger-client --save
    输出示例:
    added 15 packages in 1s
  6. 编辑函数代码。
    代码内容如下所示:
    var initTracer = require('jaeger-client').initTracer;
    var spanContext = require('jaeger-client').SpanContext;
    
    
    module.exports.handler = function(event, context, callback) 
    {
        console.log('invoking...',context.tracing);
    
        var config = {
            serviceName: 'e2e-test',
            reporter: {
                // Provide the traces endpoint; this forces the client to connect directly to the Collector and send
                // spans over HTTP
                collectorEndpoint: context.tracing.jaegerEndpoint,
                flushIntervalMs: 10,
            },
            sampler: {
                type: "const",
                param: 1
            },
        };
        var options = {
            tags: {
                'version': 'fc-e2e-tags',
            },
        };
        var tracer = initTracer(config, options);
        var invokSpanContextStr = context.tracing.openTracingSpanContext;
        console.log('spanContext', invokSpanContextStr);
        var invokSpanContext = spanContext.fromString(invokSpanContextStr);
        var span = tracer.startSpan("CustomSpan", {
            childOf: invokSpanContext
        });
        span.finish();
        var params = {
            openTracingSpanContext: context.tracing.openTracingSpanContext,
            openTracingSpanBaggages: context.tracing.openTracingSpanBaggages,
            jaegerEndpoint: context.tracing.jaegerEndpoint
        }
       callback(null,'success')
    }
  7. 安装依赖。
    1. 执行以下命令,进入项目目录:
      cd ..
    2. 执行以下命令,安装依赖:
      s build --use-docker
      输出示例:
      [2021-11-12T18:33:43.856] [INFO ] [S-CLI] - Start ...
      [2021-11-12T18:33:44.677] [INFO ] [FC-BUILD] - Build artifact start...
      [2021-11-12T18:33:44.701] [INFO ] [FC-BUILD] - Use docker for building.
      [2021-11-12T18:33:44.988] [INFO ] [FC-BUILD] - Build function using image: registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-nodejs12:build-1.9.21
      [2021-11-12T18:33:45.011] [INFO ] [FC-BUILD] - skip pulling image registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-nodejs12:build-1.9.21...
      [2021-11-12T18:33:47.915] [INFO ] [FC-BUILD] - Build artifact successfully.
      
      Tips for next step
      ======================
      * Invoke Event Function: s local invoke
      * Invoke Http Function: s local start
      * Deploy Resources: s deploy
      End of method: build
  8. 执行以下命令,部署项目:
    s deploy -y
    输出示例:
    [2021-11-12T18:35:26.015] [INFO ] [S-CLI] - Start ...
    [2021-11-12T18:35:26.633] [INFO ] [FC-DEPLOY] - Using region: cn-hangzhou
    [2021-11-12T18:35:26.634] [INFO ] [FC-DEPLOY] - Using access alias: default
    [2021-11-12T18:35:26.634] [INFO ] [FC-DEPLOY] - Using accessKeyID: LTAI4G4cwJkK4Rza6xd9****
    [2021-11-12T18:35:26.634] [INFO ] [FC-DEPLOY] - Using accessKeySecret: eCc0GxSpzfq1DVspnqqd6nmYNN****
     Using fc deploy type: sdk, If you want to deploy with pulumi, you can [s cli fc-default set deploy-type pulumi] to switch.
    [2021-11-12T18:35:26.875] [INFO ] [FC-DEPLOY] - Checking Service fc-deploy-service exists
    [2021-11-12T18:35:27.202] [INFO ] [FC-DEPLOY] - Checking Function event-nodejs12 exists
    [2021-11-12T18:35:27.286] [INFO ] [FC-DEPLOY] - Fc detects that you have run build command for function: event-nodejs12.
    [2021-11-12T18:35:27.290] [INFO ] [FC-DEPLOY] - Using codeUri: /test/jjyy/start-fc-event-nodejs12/.s/build/artifacts/fc-deploy-service/event-nodejs12
    [2021-11-12T18:35:27.293] [INFO ] [FC-DEPLOY] - Fc add/append some content to your origin environment variables for finding dependencies generated by build command.
    {
      "LD_LIBRARY_PATH": "/code/.s/root/usr/local/lib:/code/.s/root/usr/lib:/code/.s/root/usr/lib/x86_64-linux-gnu:/code/.s/root/usr/lib64:/code/.s/root/lib:/code/.s/root/lib/x86_64-linux-gnu:/code/.s/root/python/lib/python2.7/site-packages:/code/.s/root/python/lib/python3.6/site-packages:/code:/code/lib:/usr/local/lib",
      "PATH": "/code/.s/root/usr/local/bin:/code/.s/root/usr/local/sbin:/code/.s/root/usr/bin:/code/.s/root/usr/sbin:/code/.s/root/sbin:/code/.s/root/bin:/code:/code/node_modules/.bin:/code/.s/python/bin:/code/.s/node_modules/.bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/bin",
      "NODE_PATH": "/code/node_modules:/usr/local/lib/node_modules",
      "PYTHONUSERBASE": "/code/.s/python"
    }
     Make service fc-deploy-service success.
     Make function fc-deploy-service/event-nodejs12 success.
    [2021-11-12T18:35:37.661] [INFO ] [FC-DEPLOY] - Checking Service fc-deploy-service exists
    [2021-11-12T18:35:37.718] [INFO ] [FC-DEPLOY] - Checking Function event-nodejs12 exists
    
    Tips for next step
    ======================
    * Display information of the deployed resource: s info
    * Display metrics: s metrics
    * Display logs: s logs
    * Invoke remote function: s invoke
    * Remove Service: s remove service
    * Remove Function: s remove function
    * Remove Trigger: s remove trigger
    * Remove CustomDomain: s remove domain
    
    
    
    fc-deploy-test:
      region:   cn-hangzhou
      service:
        name: fc-deploy-service
      function:
        name:       event-nodejs12
        runtime:    nodejs12
        handler:    index.handler
        memorySize: 128
        timeout:    60
  9. 结果验证。
    在函数计算控制台查看调用链,可以看到您刚创建的自定义Span与函数计算的系统Span连接起来。user-defined-span

使用OpenTelemetry

本文以Python运行时为例,介绍如何通过Serverless Devs创建自定义Span,创建并部署函数的步骤。

说明 您可以使用Serverless Devs安装依赖包,并打包部署到函数计算,您也可以通过其他方式打包并部署。Serverless Devs的更多信息,请参见什么是Serverless Devs
  1. 创建代码目录。
    mkdir opentelemetry-demo
  2. 进入代码目录。
    cd opentelemey-demo
  3. 初始化Python运行时模板。
    1. 执行以下命令,初始化Python 3的项目:
      s init devsapp/start-fc-event-python3
      输出示例:
       Serverless Awesome: https://github.com/Serverless-Devs/package-awesome
      
       Please input your project name (init dir) (start-fc-event-python3)
    2. 设置项目名称,然后按回车键。
      Serverless Devs已默认为您生成一个名为start-fc-event-python3的项目,您可按需修改该名称,本文以默认的项目名称为例。
      输出示例:
       Serverless Awesome: https://github.com/Serverless-Devs/package-awesome
      
       Please input your project name (init dir) start-fc-event-python3
       file decompression completed
       please select credential alias (Use arrow keys)
      ❯ default
    3. 按需选择别名,然后按回车键。
    4. 按需选择是否部署该项目。
      由于本示例介绍的项目还需安装依赖,所以在是否立即部署该项目?(Y/n)后设置n选择不部署该项目。
  4. 安装OpenTelemetry依赖。
    1. 执行以下命令,进入代码目录:
      cd start-fc-event-python3/code
    2. 在代码目录中创建requirements.txt文件,然后编辑该文件,文件内容如下所示:
      opentelemetry-api==1.6.2
  5. 编辑函数代码。
    执行以下命令,编辑函数代码:
    vim index.py
    函数代码内容如下所示:
    # -*- coding: utf-8 -*-
    import logging
    import time
    from opentelemetry import trace
    from opentelemetry.exporter import jaeger
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
    from opentelemetry.trace import set_span_in_context
    
    trace.set_tracer_provider(TracerProvider())
    tracer = trace.get_tracer(__name__)
    
    
    def handler(event, context):
        logger = logging.getLogger()
        logger.info("start to init tracer")
        init_tracer(context.tracing.jaeger_endpoint)
        jaeger_span_context = context.tracing.span_context
        fc_invocation_span = get_fc_span(jaeger_span_context)
        with fc_invocation_span as parent:
            print('Hello world!')
        context = set_span_in_context(parent)
        child = tracer.start_span("child", context=context)
        # print(child)
        time.sleep(0.1)
        child.end()
        return 'hello world'
    
    
    def init_tracer(endpoint):
        jaeger_exporter = jaeger.JaegerSpanExporter(
            service_name='opentelemetry-service',
            collector_endpoint=endpoint,
            transport_format='thrift'  # optional
        )
    
        # Create a BatchExportSpanProcessor and add the exporter to it
        span_processor = BatchExportSpanProcessor(jaeger_exporter)
    
        # add to the tracer
        trace.get_tracer_provider().add_span_processor(span_processor)
    
    
    def get_fc_span(jaeger_span_context):
        jaeger_span_context_arr = jaeger_span_context.split(":")
        tid = int(jaeger_span_context_arr[0], 16)
        sid = int(jaeger_span_context_arr[1], 16)
        fid = int(jaeger_span_context_arr[3], 16)
    
        span_context = trace.SpanContext(
            trace_id=tid,
            span_id=sid,
            is_remote=True,
            trace_flags=trace.TraceFlags(fid),
            trace_state=[],
        )
        return trace.DefaultSpan(span_context)
    注意 当您编辑好函数代码后,请执行以下命令,然后按回车键,退出编辑页面:
    :WQ
  6. 安装依赖。
    1. 执行以下命令,进入项目目录:
      cd ..
    2. 执行以下命令,安装依赖:
      s build --use-docker
      输出示例:
      [2021-11-12T18:53:05.818] [INFO ] [S-CLI] - Start ...
      [2021-11-12T18:53:06.638] [INFO ] [FC-BUILD] - Build artifact start...
      [2021-11-12T18:53:06.659] [INFO ] [FC-BUILD] - Use docker for building.
      [2021-11-12T18:53:06.888] [INFO ] [FC-BUILD] - Build function using image: registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:build-1.9.21
      [2021-11-12T18:53:06.942] [INFO ] [FC-BUILD] - skip pulling image registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:build-1.9.21...
      [2021-11-12T18:53:10.570] [INFO ] [FC-BUILD] - Build artifact successfully.
      
      Tips for next step
      ======================
      * Invoke Event Function: s local invoke
      * Invoke Http Function: s local start
      * Deploy Resources: s deploy
      End of method: build
  7. 部署项目。
    执行以下命令,部署项目:
    s deploy -y
    输出示例:
    [2021-11-12T18:55:02.640] [INFO ] [S-CLI] - Start ...
    [2021-11-12T18:55:03.455] [INFO ] [FC-DEPLOY] - Using region: cn-hangzhou
    [2021-11-12T18:55:03.456] [INFO ] [FC-DEPLOY] - Using access alias: default
    [2021-11-12T18:55:03.456] [INFO ] [FC-DEPLOY] - Using accessKeyID: LTAI4G4cwJkK4Rza6xd9****
    [2021-11-12T18:55:03.457] [INFO ] [FC-DEPLOY] - Using accessKeySecret: eCc0GxSpzfq1DVspnqqd6nmYNN****
     Using fc deploy type: sdk, If you want to deploy with pulumi, you can [s cli fc-default set deploy-type pulumi] to switch.
    [2021-11-12T18:55:04.142] [INFO ] [FC-DEPLOY] - Checking Service fc-deploy-service exists
    [2021-11-12T18:55:04.722] [INFO ] [FC-DEPLOY] - Checking Function event-py3 exists
    [2021-11-12T18:55:04.831] [INFO ] [FC-DEPLOY] - Fc detects that you have run build command for function: event-py3.
    [2021-11-12T18:55:04.831] [INFO ] [FC-DEPLOY] - Using codeUri: /test/jjyy/opentelemetry-demo/start-fc-event-python3/.s/build/artifacts/fc-deploy-service/event-py3
    [2021-11-12T18:55:04.835] [INFO ] [FC-DEPLOY] - Fc add/append some content to your origin environment variables for finding dependencies generated by build command.
    {
      "LD_LIBRARY_PATH": "/code/.s/root/usr/local/lib:/code/.s/root/usr/lib:/code/.s/root/usr/lib/x86_64-linux-gnu:/code/.s/root/usr/lib64:/code/.s/root/lib:/code/.s/root/lib/x86_64-linux-gnu:/code/.s/root/python/lib/python2.7/site-packages:/code/.s/root/python/lib/python3.6/site-packages:/code:/code/lib:/usr/local/lib",
      "PATH": "/code/.s/root/usr/local/bin:/code/.s/root/usr/local/sbin:/code/.s/root/usr/bin:/code/.s/root/usr/sbin:/code/.s/root/sbin:/code/.s/root/bin:/code:/code/node_modules/.bin:/code/.s/python/bin:/code/.s/node_modules/.bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/bin",
      "NODE_PATH": "/code/node_modules:/usr/local/lib/node_modules",
      "PYTHONUSERBASE": "/code/.s/python"
    }
     Make service fc-deploy-service success.
     Make function fc-deploy-service/event-py3 success.
    [2021-11-12T18:55:10.693] [INFO ] [FC-DEPLOY] - Checking Service fc-deploy-service exists
    [2021-11-12T18:55:10.737] [INFO ] [FC-DEPLOY] - Checking Function event-py3 exists
    
    Tips for next step
    ======================
    * Display information of the deployed resource: s info
    * Display metrics: s metrics
    * Display logs: s logs
    * Invoke remote function: s invoke
    * Remove Service: s remove service
    * Remove Function: s remove function
    * Remove Trigger: s remove trigger
    * Remove CustomDomain: s remove domain
    
    
    
    fc-deploy-test:
      region:   cn-hangzhou
      service:
        name: fc-deploy-service
      function:
        name:       event-py3
        runtime:    python3
        handler:    index.handler
        memorySize: 128
        timeout:    60
  8. 结果验证。
    在函数计算控制台查看调用链,可以看到您刚创建的自定义Span与函数计算的系统Span连接起来。cold-start