You need to enable JavaScript to run this app.
导航

自定义事件/自定义日志

最近更新时间2023.12.15 10:25:04

首次发布时间2022.06.20 11:34:32

自定义事件和自定义日志是APMPlus PC提供的埋点功能,支持多进程多实例调用。自定义事件记录数值型数据,如cpu使用率指标,启动耗时指标等等。自定义日志记录字符串型数据,一般用于记录用户行为,产品行为,用于单点追查用户反馈的问题等等。自定义事件/自定义日志都可以在APMPlus PC的日志查询中查看。

接入要求

  • 提供有权限的文件夹绝对路径,作为Parfait初始化时的Rootpath,parfait在此路径下存储自定义事件/自定义日志。
  • 初始化Parfait SDK。持有初始化成功的parfait_wrapper_ptr指针。

注意

单条自定义事件/自定义日志长度是有限制的,超出限制可能导致写入失败。

  • 自定义事件下Category+Metric+Extra的总大小不要超过900KB。
  • 自定义日志下Category+Log的总大小不要超过900KB。

全部流程

  1. 在APMPlus PC平台上创建项目。
  2. 初始化SDK。
  3. 开启间隔循环上报。
  4. 写入自定义事件/自定义日志。
  5. 过一段时间后,数据上传。具体什么时候上传,是依据业务方设置的Report Interval & Recorder Flush Interval而定的。
  6. 在APMPlus PC平台的日志查询上搜查自定义事件/自定义日志。
  7. 问题排查。
    如果没有查询到结果,一般是以下原因:
    • 数据未写入:查看RootPathName路径下是否有lock/prepare/ready文件夹生成,一般是因为SDK未初始化,或者RootPathName设置不当,没有写入数据的权限。
    • 数据未上报:未调用Upload()或者UploadWithFlushImmediately()方法上传数据。
    • 平台数据堆积:数据已上报但是未展示,请联系研发人员进行反馈。

写入数据

自定义事件

  1. 创建自定义事件recorder。您可以长期持有此recorder。

    enum RECORD_INTERVAL {
        INTERVAL_1  = 1 * 1000,  // 最高优先级
        INTERVAL_10  = 10 * 1000, 
        INTERVAL_15  = 15 * 1000, 
        INTERVAL_30  = 30 * 1000 // 最低优先级
    };
    
    /**
     * 生成‘自定义事件’的recorder,业务方可用返回的recorder写自定义事件
     * @param  interval 数据flush间隔,flush越短,越快被上报
     * @param  service_name 事件名称
     * @return  ‘自定义事件’的recorder指针
     */
    ParfaitRecorderBase* CreateRecorder(enum RECORD_INTERVAL interval, const char* service_name);
    
    • interval:数据flush的间隔,可理解为优先级,间隔越短,优先级越高,越能更快被上报。
    • service_name:事件名称,可在日志查询中查看。
  2. 调用WriteXXX()方法记录Category、Metric、Extra数据。

    数据

    说明

    示例

    Category

    (optional)可枚举数据类型。

    • key:value中的value必须是字符串类型。
    • 用于过滤metrics数据。主要用于指标查询中,给同一事件下的数据分组。
    • 不支持嵌套json数据。
    {
    "is_scanning": "false",
    "error_code:" "-1",
    "file_type": "txt"
    }
    

    Metric

    数据指标。

    • key:value中的value必须是整形/浮点形而不是字符串或者别的数据类型,不然上报成功,但是平台搜不到。
    • 不支持嵌套json数据。
    {
    "cpu": 0.01851585025,
    "os_use_cpu": 4,
    "os_use_memory": 9205.6953125
    }
    

    Extra

    备注信息。

    • key:value中的value必须是字符串类型。
    • 不支持嵌套json数据。
    {
    "info": "This is extra info."
    }
    
    • 传入的参数必须是已序列化的json数据。最后调用DoRecord()确认写入数据。可重复这步写入新数据。
    • 该步骤只是写入数据,并不代表数据上传。DoRecord()后不会清空Category、Metric、Extra数据。如果下次写事件时,不需要写入Extra数据,需要显示调用WriteExtra()清除Extra。
      示例代码:
    ParfaitRecorderBase& ParfaitRecorderBase::WriteCategory(char *json);
    ParfaitRecorderBase& ParfaitRecorderBase::WriteMetric(char *json); 
    ParfaitRecorderBase& ParfaitRecorderBase::WriteExtra(char *json);
    // 确认写入,开启上传功能后Parfait会自动上传
    void ParfaitRecorderBase::DoRecord();
    
  3. 没有写入需求/进程退出时,调用DestroyRecorder销毁Recorder,防止内存泄漏。

    // 销毁CreateRecorder方法生成的自定义事件Recorder,不然会内存泄漏
    void ParfaitWrapperBase::DestroyRecorder(ParfaitRecorderBase* recorder);
    

    示例代码:

    // 1.初始化Parfait SDK,得到parfait_wrapper指针
    // 2.创建名为"your_service"事件recorder
    parfait::ParfaitRecorderBase* recorder = parfait_wrapper_ptr->CreateRecorder(parfait::INTERVAL_10, "your_service");
    // 3.写入json数据
    char* category = "{\n"
        "    \t\t\"category_key\" : \"1\",\n"
        "    \t}";
    char* mertic = "{\n"
        "    \t\t\"metric_key\" : 1,\n"
        "    \t}";
    char* extra = "{\n"
        "    \t\t\"extra_key\" : \"1\",\n"
        "    \t}";
    recorder->WriteCategory(category)
              .WriteMetric(mertic)
              .WriteExtra(extra)
              .DoRecord();
            
    // 4.继续写入数据,这次只写metric数据
    char* mertic2 = "{\n"
        "    \t\t\"metric_key\" : 2,\n"
        "    \t}";
    
    
    // 显式调用WriteCategory("") & WriteExtra("") 覆盖数据
    recorder->.WriteCategory("")
              .WriteMetric(mertic)
              .WriteExtra("")
              .DoRecord();
     
    // 5.应用退出,销毁recorder
    parfait_wrapper_ptr->DestroyRecorder(recorder);
    

自定义日志

  1. 创建自定义事件log recorder。您可以长期持有此log recorder。

    enum LOG_RECORD_LEVEL {
      LOG_VERBOSE, 
      LOG_DEBUG, 
      LOG_INFO, 
      LOG_WARN, 
      LOG_ERROR
    
    };
    /**
     * 新接口,生成‘日志查询’的log recorder,业务方可用返回的log recorder写指标数据
     * @param  interval 指标flush间隔,flush越短越快被上报
     * @param  log_level 日志类型
     * @return  ‘日志查询’的log recorder指针
     */
    ParfaitLogRecorderBase* ParfaitWrapperBase::CreateLogRecorder(enum RECORD_INTERVAL interval, enum LOG_RECORD_LEVEL log_level);
    
    • interval:数据flush的间隔,可理解为优先级,间隔越短,优先级越高,越能更快被上报。和自定义事件的interval一样。
    • log_level:日志等级。
  2. 记录Category、Log数据。

    数据

    说明

    示例

    Category

    (optional)可枚举数据类型。

    • key:value中的value必须是字符串类型。
    • 不支持嵌套json数据。
    {
    "is_scanning": "false"
    }
    

    Log

    日志内容,传入任意字符串即可。

    “This is a test log.”

    • 传入的数据必须为已序列化的json数据。最后调用DoRecord确认写入数据。可重复这步写入新数据。
    • 该步骤只是写入,并不代表数据上传。DoRecord()后不会清空Category、Log数据。如果下次写事件时,不需要写入Category数据,需要显示调用WriteCategory()清除Category。
      示例代码:
    // WriteCategory()函数必须传入序列化好的json数据,切记!!!
    ParfaitLogRecorderBase& ParfaitRecorderBase::WriteCategory(char *json);
    ParfaitLogRecorderBase& ParfaitRecorderBase::WriteLog(char *log); 
    
    // 确认写入,开启上传功能后Parfait会自动上传
    void ParfaitLogRecorderBase::DoRecord();
    
  3. 没有写入需求/进程退出时,调用DestroyLogRecorder销毁LogRecorder,防止内存泄漏。

    /**
     * 新接口,回收‘日志查询’的log recorder
     * @param  recorder CreateLogRecorder返回的指针
     */
    void ParfaitWrapperBase::DestroyLogRecorder(ParfaitLogRecorderBase* recorder);
    

    示例代码:

    // 1.初始化Parfait SDK,得到parfait_wrapper指针
    // 2.创建info级别的log recorder
    parfait::ParfaitLogRecorderBase* log_recorder = parfait_wrapper_ptr->CreateLogRecorder(parfait::INTERVAL_10, parfait::LOG_INFO);
    
    // 3.写入第一条日志
    char* category = "{\n"
                      "    \t\t\"category\" : \"1\",\n"
                      "    \t}";
     
    log_recorder->WriteCategory(buff1)
                 .WriteLog("log hahahaha")
                 .DoRecord();
                 
    
    // 4.写入第二条日志,只用写log
    // 显式调用WriteCategory("")覆盖数据
    log_recorder->WriteCategory("")
                 .WriteLog("log hahahaha test2")
                 .DoRecord();
    
    
    // 5.应用退出/不再写入log,销毁log_recorder
    parfait_wrapper_ptr->DestroyLogRecorder(log_recorder);
    

上报数据

业务写入自定义事件/自定义日志后,数据尚未上传。有两种上传方式:

  • (推荐)Parfait自动间隔循环上传数据,业务方不需要关心数据上报时机。间隔上报时间可由业务方设置,在初始化调用Global Env的SetReportInterval方法设置。Parfait退出时间隔上报才可停止。这种方式适合数据量大,频繁打点的业务。

    注意

    多parfait实例,多进程的情况下,同一aid只要有一个parfait实例调用Upload即可。

    /**
     * 触发自定义事件/自定义日志/性能监控数据/网络监控数据的自动间隔循环上传
     **/
    void ParfaitWrapperBase::Upload();
    
    示例代码:
    parfait_wrapper_ptr->Upload();
    
  • 业务调用UploadWithFlushImmediately()接口主动触发一次上报。此方法适用于少量数据写入,避免间隔循环上报带来的性能消耗。

    注意

    此接口实际上并非同步接口,所以在进程退出时调用可能不生效。

    /**
     * 即刻触发一次flush+upload指标&日志数据
     **/
    void ParfaitWrapperBase::UploadWithFlushImmediately();
    
    示例代码:
    parfait_wrapper_ptr->UploadWithFlushImmediately();
    

查询/消费

查询数据

数据上报后2min~4min后,可以在平台上查询和消费数据。

  1. 在APMPlus PC平台找到自己aid对应的项目(没有项目请新建一个项目)。
  2. 进入项目详情页后,单击右侧的日志查询
  3. 输入对应的did或uid,选择目标时间段,选中自定义事件/自定义日志,即可搜查数据。

特殊场景支持

同一进程内多aid打点

假设A业务的aid是6666,B业务aid为7777。那么:
A业务创建一个AID为6666的parfait全局环境变量和parfait示例环境变量,并持有aid为6666的parfait_wrapper6666指针写入数据。
B业务创建一个AID为7777的parfait全局环境变量和parfait示例环境变量,并持有aid为7777的parfait_wrapper7777指针写入数据。
由于二者数据存放路径不一致,因此,AID6666和AID7777都需要调用Upload()方法开启自己的数据间隔循环上报。

多进程打点

如果业务为多进程应用,子进程也需要进行打点。有两种方式:

  • 基于IPC通信,子进程传数据给主进程进行打点。
  • 子进程也接入Parfait,初始化流程和主进程一致。如果和主进程为同一AID + Rootpath,那么打点进程只需要管理进程SDK初始化+打点,不用管任何的上报逻辑。