关于c++:TARS-染色日志|收集记录特定日志

7次阅读

共计 8344 个字符,预计需要花费 21 分钟才能阅读完成。

作者|Eaton

导语|
记日志能够说是程序猿 / 媛日常开发中的粗茶淡饭了。在日常业务场景中,常常须要剖析特定用户的日志,个别的日志记录形式很难满足需要,有什么解决办法呢?TARS 框架中蕴含染色日志的性能,可能记录特定用户的日志,优雅地解决这一问题。本文将会介绍染色日志的原理和性能,以及如何在 TARS 中应用染色日志。

目录

  • 背景
  • 初识染色日志
  • TARS 染色性能概述
  • 染色日志初体验

    • 被动关上染色日志
    • 被动关上染色日志
    • 增加特定逻辑
  • 总结

背景

很多业务场景中,须要对特定用户的行为进行追踪,比方局部用户反馈服务有 BUG,须要排查,但发现只是个例,要独自找出这些用户的日志进行剖析;又或是 APP 上线了一个新的性能,先对一部分用户凋谢进行测试,须要追踪这部分用户的行为等。

依照个别形式,要在曾经记录的日志中检索这部分用户的日志。看起来挺简略,然而在微服务的大背景下,服务间调用关系简单(如下图),日志扩散在各个服务节点上。对于一次调用,须要先获取调用链,再找出具体服务调用的节点,而后从节点上获取日志,这个过程十分繁琐。

另外,日志的记录会耗费程序的性能,占用用户的计算资源。因而在正式环境中,日常业务都会管制日志打印的量,确保日志打印不影响用户服务。而在对特定用户行为进行剖析时,往往须要记录额定的日志,能力满足剖析等需要,间接减少日志的打印显然不太事实。

可见,传统的日志记录形式无奈满足对特定用户行为的日志记录,染色日志就是来解决这一问题的。

初识染色日志

什么是染色日志呢?在一个调用链外面,标记出某个特定需要的过程,让整个调用链里的上下文信息始终被传输上来,就像一开始被标记染色一样,这种标记日志的形式,咱们叫它染色日志。

简略来说,就是咱们只想要某几个用户的日志信息,通过染色日志把这几个用户的日志另外打印一份,并收集在同一个中央,这样咱们在一个中央就能查找到这些染色用户的日志。

咱们能够用染色日志定位一些特定的地位,也能够定一些特定的逻辑。比方某微信用户反馈语音发送存在问题,通过对用户 ID(微信号)进行染色,后端服务接管到染色用户的申请后,就会将该用户本次调用的处理过程日志打印进去,能够十分不便地获取咱们须要的要害信息。除了打印日志,还能够通过染色执行特定逻辑,比方新上线一个性能,凋谢给一部分用户应用,通过染色,后端服务能够判断用户是否在测试名单中,再执行相应的服务逻辑。

TARS 染色性能概述

TARS 框架反对染色日志性能,能够在某服务某接口中对特定用户号码的音讯进行染色,不便地实时观察该用户引起后续所有相干调用音讯流的日志。下图为 TARS 中的染色流程

染色日志关上后,在业务中通过指定染色的 key 值,例如指定 QQ 号为 123456 的用户,后续该用户的申请都会在框架中被主动染色,并通过日志服务(tarslog)集中打印染色日志。

咱们只须要到 tarslog 服务所在的服务器上查看相应的染色日志即可,具体的门路个别为

/usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/

该目录下个别蕴含两种日志文件:染色的滚动日志和染色的按天日志,日志文件名格局别离为 tars_dyeing.dyeing_roll_yyyymmdd.log, tars_dyeing.dyeing_day_yyyymmdd.log,比方:

# 染色滚动日志
tars_dyeing.dyeing_roll_20201103.log
# 染色按天日志
tars_dyeing.dyeing_day_20201103.log

滚动日志是服务的本地日志,个别用于记录服务调试信息;按天日志是服务的近程日志,个别用于记录重要的业务信息。开启染色后,如果接管到染色的申请,两种日志都会额定打印一份到 tarslog,只记录染色申请打印的日志,每天保留一个文件。

对于滚动日志和按天日志的用法以及更多信息,能够看到官网文档中日志局部,这里不再赘述。

染色日志初体验

TARS 框架的染色日志有被动关上和被动关上两种形式。接下来让咱们通过实例,理解如何通过这两种形式在 TARS 中应用染色日志。本章中应用的实例源码都能够在这里找到。

被动关上染色日志

被动关上,指的是在发动申请的客户端的业务代码中,被动关上框架的染色日志开关。具体流程如下:

  1. 在客户端程序适当的中央申明染色日志开关 tars::TarsDyeingSwitch 的对象。
  2. 调用该开关对象的 enableDyeing 办法即可关上染色日志。被调用的服务也会主动关上染色开关,并打印日志到 tarslog。如果该被调服务还要调用其余服务,则主动传递给下个服务。
  3. 在染色日志开关敞开前,客户端打印的所有日志和被调用的服务打印的日志,都会额定打印一份到日志服务 tarslog
  4. 客户端开关对象析构,染色日志敞开,后续的调用和日志打印不再生成染色日志。

上面,咱们通过一个实例来理解如何在客户端(主调方)中被动关上染色日志。

实例

这里以 C++ 为例,依照方才介绍的流程,开启染色日志并调用 TARS 服务。

在开始之前,咱们须要先筹备一个 TARS 服务,供之后的客户端调用,源码见 TestServer 源码。咱们创立一个服务,利用名为 TestApp,服务名 TestServerObj 名为 TestTest.tars 文件中定义的接口如下

module TestApp
{

interface Test
{int test(string id, out string output);
};

};

TestImp.hTestImp.cpptest 接口的定义和实现如下

// TestImp.h
virtual int test(const std::string &id, std::string &output, tars::TarsCurrentPtr current);

//TestImp.cpp
int TestImp::test(const std::string &id, std::string &output, tars::TarsCurrentPtr current)
{
    // 打印本地日志
    TLOGDEBUG(__FILE__ << "|" << __LINE__ << "|" << "id:" << id << endl);
    output = id;
    return 0;
}

构建该服务并在 TarsWeb 上部署公布即可。

对于 TARS 服务的创立与部署,参考文档 TARS 开发入门,这里不再赘述。

接下来,咱们编写一个简略的客户端 Demo,实现关上染色日志、调用 TARS 服务接口的流程,如下

#include <iostream>
#include <string>

#include "servant/Communicator.h"
#include "servant/TarsLogger.h"
#include "util/tc_option.h"
#include "util/tc_file.h"

#include "Test.h"

using namespace std;
using namespace tars;

int main(int argc,char ** argv)
{
    try
    {   // 初始化通信代理,用于调用服务
        CommunicatorPtr comm = new Communicator();
        comm->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h 192.168.0.121 -p 17890 -t 10000");
        TarsRollLogger::getInstance()->setLogInfo("TestApp", "TestServer", "./log", 100000, 10, comm, "tars.tarslog.LogObj");
        TarsRollLogger::getInstance()->sync(false);
        TarsTimeLogger::getInstance()->setLogInfo(comm, "tars.tarslog.LogObj", "TestApp", "TestServer", "./log");

        {   // 在关上染色日志之前,打印日志,这条日志只会打印到本地日志中。TLOGDEBUG     (__FILE__ << "|" << __LINE__ << "|" << "Test Before Dyeing" << endl);
            DLOG        << __FILE__ << "|" << __LINE__ << "|" << "D/Test Before Dyeing" << endl;
        }

        {   // 申明一个染色日志开关对象
            TarsDyeingSwitch dye;
            // 关上染色日志
            dye.enableDyeing();

            /* 在关上染色日志之后,打印日志,会在本地日志和染色日志中看到
             * TLOGDEBUG: 打印本地 DEBUG 日志
             *      DLOG: 打印按天的近程日志
             */
            {TLOGDEBUG(__FILE__ << "|" << __LINE__ << "|" << "Test After Dyeing" << endl);
                DLOG   << __FILE__ << "|" << __LINE__ << "|" << "D/Test After Dyeing" << endl;
            }

            // 生成调用代理
            TestApp::TestPrx prx = comm->stringToProxy<TestApp::TestPrx>("TestApp.TestServer.TestObj");
            string output;
            // 调用 test 接口
            prx->test("hello", output);
            cout << output << endl;
        }

        // 染色日志开关曾经析构,染色性能生效,当前的日志不会打印到染色日志中
        TLOGDEBUG(__FILE__ << "|" << __LINE__ << "|" << "~Dyeing" << endl);
        DLOG   << __FILE__ << "|" << __LINE__ << "|" << "D/~Dyeing" << endl;
    }
    catch(exception& e)
    {cerr << "exception:" << e.what() << endl;
    }
    catch (...)
    {cerr << "unknown exception." << endl;}
    sleep(10); // 期待异步写日志线程同步日志数据到 logserver
    return 0;
}

能够看到,该客户端中蕴含了三次日志打印,只有一次在染色日志开启期间打印。同时,染色日志开启期间,调用了服务 TestApp.TestServer.TestObj 的接口 test

编译并执行客户端后,咱们就能够在日志服务所在服务器的门路 /usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/ 中,找到染色日志文件,如 tars_dyeing.dyeing_roll_20201104.logtars_dyeing.dyeing_day_20201104.log

  • tars_dyeing.dyeing_roll_20201104.log
# 应用 TLOGDEBUG 打印的滚动日志
192.168.0.121|TestApp.TestServer|2020-11-04 03:56:53|139734968739712|DEBUG|main.cpp|37|Test After Dyeing
  • tars_dyeing.dyeing_day_20201104.log
# 应用 DLOG 打印的近程日志
192.168.0.121|TestApp.TestServer|2020-11-04 03:56:53|main.cpp|38|D/Test After Dyeing

能够看出,染色日志文件中,只有在 TarsDyeingSwitch dye 作用域内打印的日志。

有趣味的读者能够下载客户端源码自行尝试,将其中的 IP 替换为本人服务所在节点的 IP 即可。

被动关上染色日志

被动关上,指的是在申请的服务端事后设定染色的条件,判断传递的 key 值,由服务端来关上本身的染色日志开关,相比于被动关上的形式,被动关上不须要批改客户端 (调用方) 业务代码,是一种非侵入式的形式。具体流程如下:

  1. 在 tars 接口文件中,通过 routekey 来设置接口的某个参数为 key,如用户 ID;
  2. 在 TarsWeb 通过框架命令传入须要染色的用户 ID 的值以及服务 Obj 和接口名;
  3. 服务收到匹配的申请后,对申请包进行染色解决,并打印日志到日志服务 tarslog
  4. 服务处理过程如果持续调用其余 TARS 服务,则主动传递给下个服务。

接下来咱们通过一个实例,理解如何通过被动形式关上染色日志。

实例

  • 将接口 test 的参数 id 设置为染色 key

这里咱们持续应用后面创立的 TARS 服务 Demo。在 tars 接口文件中,批改接口 test,应用 routekey 指定其中的参数 id 为染色 key,如下

    int test(routekey string id, out string output);

接着,替换客户端 (调用方) 本来应用的 tars 文件并从新编译构建就实现了客户端的批改,无需批改业务代码。

  • 开启染色日志并设置须要染色的 key 值(testid 的值)

TARS 框架中预设了一些框架命令,可能通过 TarsWeb 平台发送。这里咱们能够通过命令 tars.setdyeing 开启染色日志,命令格局如下:

tars.setdyeing dyeingKey dyeingServant [dyeingInterface]

三个参数别离为染色 key 值(routekey 标记的参数,本例为 id),服务对象名称,接口名称(可选)。例如本文中的服务对象为 TestApp.TestServer.TestObj,染色接口名称为 test,咱们想对 id123456 的用户染色,那么能够通过治理平台公布以下命令:

tars.setdyeing 123456 TestApp.TestServer.TestObj test

该命令通过 TarsWeb 页面的 服务治理 -> 更多命令 -> 自定义命令 来发送,如图所示

若后续没有滚动日志输入,能够在此页面设置日志等级为 DEBUG

实现上述步骤,就实现了染色的关上和染色用户 ID 值的增加。

当接口 testid123456 的申请发到该服务,将会另外打印染色日志,同样保留在日志服务(tarslog)机器的门路 /usr/local/app/tars/remote_app_log/tars_dyeing/dyeing/ 下的滚动日志文件和按天日志文件中。

这里咱们能够持续应用上节的客户端,因为不须要在代码中被动申明并关上染色开关,对客户端代码进行精简,放弃原有的接口调用逻辑即可,批改后如下

#include <iostream>
#include <string>

#include "servant/Communicator.h"
#include "util/tc_option.h"
#include "util/tc_file.h"

#include "Test.h"

using namespace std;
using namespace tars;

int main(int argc,char ** argv)
{
    try
    {   // 初始化通信代理,用于调用服务(读者无需关注)CommunicatorPtr comm = new Communicator();
        comm->setProperty("locator", "tars.tarsregistry.QueryObj@tcp -h 192.168.0.121 -p 17890 -t 10000");

        // 生成调用代理
        TestApp::TestPrx prx = comm->stringToProxy<TestApp::TestPrx>("TestApp.TestServer.TestObj");
        string output;
        // 调用 test 接口, 传入染色 id: 123456
        prx->test("123456", output);
        cout << output << endl;
        // 调用 test 接口, 传入非染色 id: tars
        prx->test("tars", output);
        cout << output << endl;
    }
    catch(exception& e)
    {cerr << "exception:" << e.what() << endl;
    }
    catch (...)
    {cerr << "unknown exception." << endl;}
    return 0;
}

参考客户端源码

编译执行后,咱们能够在染色日志文件中,例如 tars_dyeing.dyeing_roll_20201104.log

192.168.0.121|TestApp.TestServer|2020-11-04 15:58:08|140356905592576|DEBUG|TestImp.cpp|31|id: 123456

增加特定逻辑

后面咱们提到过,可能在服务中为染色的用户增加特定的逻辑,接下来将持续以 TestServer 为例,介绍如何为染色用户增加特定逻辑。

实现形式其实很简略:通过判断传入的申请是否为染色申请,决定是否执行特定的逻辑即可。例如,咱们在 TestImp.cpp 中批改 TestServer 接口的实现,如果以后用户是染色用户则输入 Dyeing is on,普通用户则输入用户 id,代码如下

 int TestImp::test(const string &id, string &output, tars::TarsCurrentPtr current)
{   // 服务对象名
    string servantName =  ServerConfig::Application + "." + ServerConfig::ServerName + ".TestObj";

    // 判断是否为染色用户
    if (tars::ServantHelperManager::getInstance()->isDyeingReq(id, servantName, "test")) {
        // 染色用户返回值
        output = "Dyeing is on";
        TLOGDEBUG(__FILE__ << "|" << __LINE__ << "|" << "Test"  << endl);
        DLOG   << __FILE__ << "|" << __LINE__ << "|" << "D/Test"  << endl;
        return 0;
    }
    // 非染色用户返回用户 id
    output = id;
    TLOGDEBUG(__FILE__ << "|" << __LINE__ << "|" << "Test" << endl);

    return 0;
}

上述代码中,咱们应用 ServantHelperManager 中的 isDyeingReq 来判断申请 ID 是否染色,染色则返回 true,并在 if 中增加对染色用户执行的逻辑。isDyeingReq 须要传入三个参数,routekey 标识的入参值 (id),服务对象名(TestApp.TestServer.TestObj) 和接口名称(test)。

接下来,咱们间接应用上一节的客户端实例,其中蕴含了两次接口调用

...
        // 调用 test 接口, 传入染色 id: 123456
        prx->test("123456", output);
        cout << output << endl;
        // 调用 test 接口, 传入非染色 id: tars
        prx->test("tars", output);
        cout << output << endl;
...

后面咱们曾经在 TarsWeb 平台开启了对 123456 的染色,没有开启对 tars 的染色,编译并执行该客户端,后果如下

Dyeing is on
tars

可见 id123456 的申请胜利触发染色逻辑,而 idtars 的申请没有。

总结

染色日志填补了传统日志记录形式的有余,通过相似染色的形式,实现了对特定用户、调用链日志的集中打印,不便日志的查看和剖析。TARS 框架蕴含了染色性能,并提供了被动与被动两种关上染色日志的形式,不便用户依据需要抉择。同时,还能为特定的申请增加额定的特定逻辑,进一步扩充应用场景,如灰度公布等。

TARS 能够在思考到易用性和高性能的同时疾速构建零碎并主动生成代码,帮忙开发人员和企业以微服务的形式疾速构建本人稳固牢靠的分布式应用,从而令开发人员只关注业务逻辑,进步经营效率。多语言、麻利研发、高可用和高效经营的个性使 TARS 成为企业级产品。

TARS 微服务助您数字化转型,欢送拜访:

TARS 官网:https://TarsCloud.org

TARS 源码:https://github.com/TarsCloud

Linux 基金会官网微服务收费课程:https://www.edx.org/course/bu…

获取《TARS 官网培训电子书》:https://wj.qq.com/s2/6570357/…

或扫码获取:

正文完
 0