精华内容
下载资源
问答
  • windows驱动写日志
    千次阅读
    2018-12-13 11:02:23

    如何在windows驱动中的READ及WRITE(代码中没有贴出) 中写日志,以下代码是可以直接运行的,在win7_32位上运行没问题

    希望对大家有用

    https://blog.csdn.net/feixi7358/article/details/84984154?tdsourcetag=s_pcqq_aiomsg

    stdafx.h

    #ifndef _WIN32_WINNT		// Allow use of features specific to Windows XP or later.                   
    #define _WIN32_WINNT 0x0501	// Change this to the appropriate value to target other versions of Windows.
    #endif						
    
    #ifdef __cplusplus
    extern "C" 
    {
    #endif
    #include <fltKernel.h>
    #include <ntddk.h>
    #include <ntddstor.h>
    #include <mountdev.h>
    #include <ntddvol.h>
    
    #ifdef __cplusplus
    };
    #endif
    
    typedef struct _LOG_LIST
    {
      LIST_ENTRY listNode;  
      UNICODE_STRING msg;
    }LOG_LIST,*PLOG_LIST;
    
    
    
    FLT_PREOP_CALLBACK_STATUS
      preRead(
      __inout PFLT_CALLBACK_DATA Data,
      __in PCFLT_RELATED_OBJECTS FltObjects,
      __deref_out_opt PVOID *CompletionContext
      );
    
    
    NTSTATUS
      FilterUnload (
      __in FLT_FILTER_UNLOAD_FLAGS Flags
      );
    
    
    VOID  ThreadProc();
    VOID  StartThread();
    
    
    CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
     
      { IRP_MJ_READ,
      0,
      preRead, 
      NULL,
      },
    
    
      { IRP_MJ_OPERATION_END }
    };
    CONST FLT_REGISTRATION FilterRegistration = {
      sizeof( FLT_REGISTRATION ),         //  Size
      FLT_REGISTRATION_VERSION,           //  Version
      0,                                  //  Flags
      NULL,			    //  Context
      Callbacks,                          //  Operation callbacks
      FilterUnload,                       //  MiniFilterUnload
      NULL,						//  InstanceSetup
      NULL,				//  InstanceQueryTeardown
      NULL,                               //  InstanceTeardownStart
      NULL,                               //  InstanceTeardownComplete
      NULL,                               //  GenerateFileName
      NULL,                               //  GenerateDestinationFileName
      NULL                                //  NormalizeNameComponent
    };
    
    
    

    writelog.cpp ,我用的minifilter过滤框架,但是在写文件的时候,我用的Zw-开头的函数,会引起重入,所以的只监控了D盘,而把日志写在C盘,故可以避免重入,但最好的做法是用minifilter的API,Flt开头的函数即可

    #include "stdafx.h"
    
    #define LOG_MSG  'msg'
    
    
    #ifdef __cplusplus
    extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath);
    #endif
    
    LIST_ENTRY LogListHeader;
    //minifilter 句柄
    PFLT_FILTER gFilterHandle;
    KEVENT s_Event;
    BOOLEAN  FLAG = TRUE;
    
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath)
    {
      NTSTATUS status;
      KdPrint(("DriverEntry \n"));
    
      InitializeListHead(&LogListHeader);
    
      //注册
      status=FltRegisterFilter(DriverObject,
        &FilterRegistration,
        &gFilterHandle);
    
     // ASSERT(NT_SUCCESS(status));		
      if (NT_SUCCESS(status))
      {
        //启动过滤器
        status=FltStartFiltering(gFilterHandle);
        if(!NT_SUCCESS(status))
        {
          FltUnregisterFilter(gFilterHandle);
        }
    
      } 
    
      KeInitializeEvent(&s_Event,SynchronizationEvent,FALSE);
      StartThread();
    
      return STATUS_SUCCESS;
    }
    #ifdef __cplusplus
    }; // extern "C"
    #endif
    
    NTSTATUS FilterUnload(__in FLT_FILTER_UNLOAD_FLAGS Flags)
    {
    	FltUnregisterFilter(gFilterHandle);
        FLAG = FALSE;
        KdPrint(("卸载成功\n"));
        return STATUS_SUCCESS;
    }
    
    
    
    
    FLT_PREOP_CALLBACK_STATUS
      preRead(
      __inout PFLT_CALLBACK_DATA Data,
      __in PCFLT_RELATED_OBJECTS FltObjects,
      __deref_out_opt PVOID *CompletionContext
      )
    {
      NTSTATUS status;
      PFLT_FILE_NAME_INFORMATION nameInfo;
      UNICODE_STRING Directory_Of_Bait_files;
      UNICODE_STRING log_msg;
      UNREFERENCED_PARAMETER( FltObjects );
      UNREFERENCED_PARAMETER( CompletionContext );
      PAGED_CODE();        
      __try {	        
          status = FltGetFileNameInformation( Data,
                         FLT_FILE_NAME_NORMALIZED |
                         FLT_FILE_NAME_QUERY_DEFAULT,
                         &nameInfo );
          if (NT_SUCCESS( status )) 
          {
            FltParseFileNameInformation( nameInfo );
            RtlInitUnicodeString( &Directory_Of_Bait_files, L"\\Device\\HarddiskVolume3\\");
            RtlInitUnicodeString( &log_msg, L"\\Device\\HarddiskVolume3\\\r\n");//准备保存进程名
            if (RtlPrefixUnicodeString(&Directory_Of_Bait_files,&nameInfo->Name,TRUE))
            {
                PLOG_LIST pathListNode;
                pathListNode = (PLOG_LIST)ExAllocatePool(NonPagedPool,sizeof(LOG_LIST));
                if (pathListNode == NULL)
                {
                  KdPrint(("队列申请失败  \n"));  
                }
    
     logListNode->msg.Buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, len, LOG_MSG);
                    logListNode->msg.Length = 0;
                    logListNode->msg.MaximumLength = log_msg.Length.;
    
                RtlAppendUnicodeStringToString(&logListNode->msg,&log_msg);
                InsertTailList(&HidePathListHeader,&pathListNode->listNode);//插入队尾
                KeSetEvent(&s_Event,IO_NO_INCREMENT,FALSE);
            }
               FltReleaseFileNameInformation( nameInfo ); 
          }   
      }
    
     __except(EXCEPTION_EXECUTE_HANDLER) {
        DbgPrint("NPPreCreate EXCEPTION_EXECUTE_HANDLER\n");				
      }
      return FLT_PREOP_SUCCESS_NO_CALLBACK;
    }
    
    
    
    VOID  ThreadProc()  
    {  
      DbgPrint("CreateThread Successfully\n");  
      PLOG_LIST hideList;
      PLIST_ENTRY pListNode;
      OBJECT_ATTRIBUTES objectAttributes;
      IO_STATUS_BLOCK iostatus;
      HANDLE hfile;
      NTSTATUS  status;
      UNICODE_STRING logFileUnicodeString;
      RtlInitUnicodeString( &logFileUnicodeString, L"\\??\\C:\\1.LOG");
      while(FLAG){
        KeWaitForSingleObject(&s_Event,Executive,KernelMode,FALSE,NULL);
        while (!IsListEmpty(&HidePathListHeader))
        {
          LIST_ENTRY *pEntry = RemoveHeadList(&LogListHeader); //得到并移除第一个节点
          hideList = CONTAINING_RECORD(pEntry,LOG_LIST,listNode);
    
          InitializeObjectAttributes(&objectAttributes,
            &logFileUnicodeString,
            OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,//对大小写敏感 
            NULL, 
            NULL );
          status = ZwCreateFile( &hfile,  //创建文件
                                  FILE_APPEND_DATA,
                                  &objectAttributes, 
                                  &iostatus, 
                                  NULL,
                                  FILE_ATTRIBUTE_NORMAL, 
                                  FILE_SHARE_READ,
                                  FILE_OPEN_IF,//存在该文件则打开 ,不存在则创建
                                  FILE_SYNCHRONOUS_IO_NONALERT, 
                                  NULL, 
                                  NULL);
          if (!NT_SUCCESS(status))
          {
            KdPrint(("The file is not exist!\n"));
            ExFreePoolWithTag(hideList->msg.Buffer,LOG_MSG);
            ExFreePool(hideList);
            continue;
          }
    
          ZwWriteFile(hfile,NULL,NULL,NULL,&iostatus,hideList->msg.Buffer,hideList->msg.Length,NULL,NULL);
          ZwClose(hfile);
          ExFreePoolWithTag(hideList->msg.Buffer,LOG_MSG);
          ExFreePool(hideList);
        }
      }
    
      KdPrint(("线程函数结束\n"));
      //结束自己
     // PsTerminateSystemThread(STATUS_SUCCESS);   
      return ;
    }  
    
     VOID StartThread()
     {
        NTSTATUS status = STATUS_SUCCESS;
    	HANDLE   hThread = NULL;
    	status = PsCreateSystemThread(&hThread, //创建新线程
    		   (ACCESS_MASK)THREAD_ALL_ACCESS,
    		   NULL,
    		   NULL,//NtCurrentProcess(),线程所在地址空间的进程的handle
    		   NULL,
    		   (PKSTART_ROUTINE)ThreadProc,
    		  NULL);  //(PVOID)&kEvent    StartContext   对应ThreadProc中的参数
    	if (!NT_SUCCESS(status))
    	{
    		KdPrint(("创建失败 \n"));
    		ZwClose(hThread);
    		return ;
    	}
    	KdPrint(("创建成功 \n"));
    	ZwClose(hThread);
    	return ;
     }
    

    1.LOG中的内容

    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    \Device\HarddiskVolume3\
    

    希望对大家有帮助,只做有用的,不做垃圾;

    要转载的话请标明出处  https://blog.csdn.net/feixi7358/article/details/84984154?tdsourcetag=s_pcqq_aiomsg

    更多相关内容
  • 下面小编就为大家分享一篇c#快速本地日志方法,具有很的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • C#的LOG日志读写操作

    2020-06-02 09:01:35
    非常简单详细的C# LOG日志读写,主程序中已经为大家注释了读写的接口,直接改就可以。路径也一定要改,不然你找不到log文件了就。代码编译没有问题,有问题请百度。
  • 主要介绍了java项目打包成可执行jar用log4j将日志写在jar所在目录操作,具有很的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 赶上1024有征文活动,就一篇吧,实习的这段时间,我更加认识到日志的重要性,客户端值没传过来?看日志,服务崩溃了?看日志,没错,日志是出现异常第一个想到的东西,它记录了程序运行过程中所调用的函数,所...


    一. 前言

    哈喽,自从实习以来很久没有更文了,一是没有时间,二是实习了之后突然发现自己能写的东西也没有多少了。赶上1024有征文活动,就写一篇吧,在实习的这段时间,我更加认识到日志的重要性,客户端值没传过来?看日志,服务崩溃了?看日志,没错,日志是出现异常第一个想到的东西,它记录了程序运行过程中所调用的函数,所接受到的值,所执行的行为等等。大家也都看到这篇的标题了,我这个人有一个缺点,就是不太喜欢用别人的东西,如果有能力,我希望自己造,所以今天我们自己来动手撸一个日志库,文章重点讲实现过程,如果需要源码,可以前往github获取FdogLog,一个轻量级C++日志库,用于日志服务。

    跪求三连!


    二. 基本功能

    我们先来捋一捋这个日志库应该实现那些功能。

    1. 日志最最最基本的功能是什么,当然是打印或记录日志。
    2. 信息应该包括哪些信息,时间?运行用户?所在文件?想要显示的信息?(自定义显示信息下篇实现)
    3. 信息虽然显示丰富,但是要尽可能让代码自己获取其他信息,调用者只需要设置最主要的信息。
    4. 信息有重要等级之分,所以我们需要对信息做必要分类,提高效率。
    5. 如何实现全局尽可能简洁的调用。
    6. 如果日志库是运行在多线程环境,如何保证线程安全。(下篇实现)

    这些就是一个日志库所具备的最基本的功能,接下来继续思考,还需要什么。

    1. 怎么控制日志的行为。
    2. 如果保存在文件,如何定义文件名。
    3. 随着日志增加,文件会越来越大,如何解决。(下篇实现)

    简单规划完一个不那么完美的日志库所具备的能力,现在我们来对这几条做更详细的规划。

    1. 日志最最最基本的功能是什么,当然是打印或记录日志。
    2. 信息应该包括哪些信息,时间?运行用户?所在文件?想要显示的信息?

    当我在调用一个名为function的函数时。

    function();
    

    你希望它输出怎么样的信息。

    我被调用
    [2021-10-20 23:27:23] 我被调用
    [2021-10-20 23:27:23] INFO 我被调用
    [2021-10-20 23:27:23] INFO root 我被调用
    [2021-10-20 23:27:23] INFO root 17938 我被调用
    [2021-10-20 23:27:23] INFO root 17938 [/media/rcl/FdogIM/service.h function:8] 我被调用

    我想大部分人都会选择最后一种输出信息吧(虽然在这之前,我们都大量使用cout输出第一种),所以我们的日志应该包括时间,日志等级,运行用户,进程ID,调用函数所在文件,以及调用时所在行数。当然总会有人不想全部输出,这将在后面给出方案。

    1. 信息虽然显示丰富,但是要尽可能让代码自己获取其他信息,调用者只需要设置最主要的信息。

    2. 信息有重要等级之分,所以我们需要对信息做必要分类,提高效率。

    3. 如何实现全局尽可能简洁的调用.

    信息有重要等级之分,要可以对信息做区分,按照常见的等级之分,有:

    ERROR: 此信息输出后,主体系统核心模块不能正常工作,需要修复才能正常工作。
    WARN:   此信息输出后,系统一般模块存在问题,不影响系统运行。
    INFO:     此信息输出后,主要是记录系统运行状态等关联信息。
    DEBUG: 最细粒度的输出,除去上面各种情况后,你希望输出的相关信息,都可以在这里输出。
    TRACE:  最细粒度的输出,除去上面各种情况后,你希望输出的相关信息,都可以在这里输出。

    有了等级之分,如何实现全局尽可能简洁的调用,通俗的说就是去掉一切不必要的调用,只留下最主要的调用。

    例如:

    #include<iostream>
    #include"fdoglogger.h"  //添加日志库头文件
    
    using namespace fdog;   //日志库的命名空间
    
    int main(){
        FdogError("错误");
        FdogWarn("警告");
        FdogInfo("信息");
        FdogDebug("调试");
        FdogTrace("追踪");
        return 0;
    }
    

    你不必初始化什么信息,调用什么多余的初始化函数,只需要用这五个类似函数的东西来输出即可,同样,如果是另一个源文件,依旧是这样的调用方式(这里可以使用单一模式来实现,其意图是保证一个类仅有一个实列,并提供一个访问它的全局访问点,该实例被所有程序模块共享。就比如日志的输出。)。

    1. 如果日志库是运行在多线程环境,如何保证线程安全。

    到目前,一个基本的日志库的调用基本成形,如果在单线程,它可以很好的工作,但是到了多线程环境下,就不能保证了,第一点就是单例模式的创建,当两个线程同时去初始化时,无法保证单一实例被成功创建,第二,日志既然是输出到文件,不同线程写入文件时,如何保证写入数据不会错乱。既然写的是C++的日志输出,必然用到了cout ,cout 不是原子性的操作,所以在多线程下是不安全的,这些都是我们需要考虑到的。

    1. 怎么控制日志的行为。

    这里使用配置文件进行日志的行为规定,包括打印什么日志,输入到文件,还是终端,输出的等级,以及日志开关,等等,配置文件将在程序启动时被读取。(提醒各位千万不要写死代码,后患无穷!!!)

    1. 如果保存在文件,如何定义文件名。

    2. 随着日志增加,文件会越来越大,如何解决。

    日志的文件名由配置文件指定,但是创建时会在后面加上创建日期后缀,并且可以在配置文件中配置每隔多少天创建一个新的日志文件,如果配置中心有设置日志文件大小,则会优先大小判断,超过便创建一个新文件。


    三. 代码实现

    1. fdoglogger.h
    #ifndef FDOGLOGGER_H
    #define FDOGLOGGER_H
    #include<iostream>
    #include<fstream>
    #include<map>
    #include<mutex>
    #ifndef linux
    #include<unistd.h>
    #include<sys/syscall.h>
    #include<sys/stat.h>
    #include<sys/types.h>
    #include <pwd.h>
    #endif
    #ifndef WIN32
    //TODO
    #endif
    using namespace std;
    
    namespace fdog {
    
    #define RED   "\e[1;31m"
    #define BLUE  "\e[1;34m"
    #define GREEN "\e[1;32m"
    #define WHITE "\e[1;37m"
    #define DEFA  "\e[0m"
    
    enum class coutType: int {Error, Warn, Info, Debug, Trace};
    enum class fileType: int {Error, Warn, Info, Debug, Trace};
    enum class terminalType: int {Error, Warn, Info, Debug, Trace};
    
    struct Logger {
        string logSwitch;           //日志开关
        string logFileSwitch;       //是否写入文件
        string logTerminalSwitch;   //是否打印到终端
        string logName;             //日志文件名字
        string logFilePath;         //日志文件保存路径
        string logMixSize;          //日志文件最大大小
        string logBehavior;         //日志文件达到最大大小行为
        string logOverlay;          //日志文件覆盖时间
        string logOutputLevelFile;  //日志输出等级(file)
        string logOutputLevelTerminal;//日志输出等级
    };
    
    class FdogLogger {
    public:
        void initLogConfig();
    
        void releaseConfig();
    
        static FdogLogger* getInstance();
    
        string getCoutType(coutType coutType);
    
        bool getFileType(fileType fileCoutBool);
    
        bool getTerminalType(terminalType terminalCoutTyle);
    
        string getLogCoutTime();
    
        string getLogNameTime();
    
        string getFilePash();
    
        string getLogCoutProcessId();
    
        string getLogCoutThreadId();
    
        string getLogCoutUserName();
    
        bool createFile(string filePash);
    
        bool logFileWrite(string messages);
    
        bool bindFileCoutMap(string value1, fileType value2);
    
        bool bindTerminalCoutMap(string value1, terminalType value2);
    
    private:
        char szbuf[128];
        Logger logger;
        static FdogLogger * singleObject;
        static mutex * mutex_new;
        map<coutType, string> coutTypeMap;
        map<fileType, bool> fileCoutMap;
        map<terminalType, bool> terminalCoutMap;
    
    private:
        FdogLogger();
        ~FdogLogger();
    };
    
    #define Error1 __FDOGNAME__(Error)
    #define Warn1 __FDOGNAME__(Warn)
    #define Info1 __FDOGNAME__(Info)
    #define Debug1 __FDOGNAME__(Debug)
    #define Trace1 __FDOGNAME__(Trace)
    
    
    #define SQUARE_BRACKETS_LEFT " ["
    #define SQUARE_BRACKETS_RIGHT "] "
    #define SPACE " "
    #define LINE_FEED "\n"
    #define COLON ":"
    #define SLASH "/"
    
    #define __FDOGTIME__  FdogLogger::getInstance()->getLogCoutTime()          //时间宏
    #define __FDOGPID__   FdogLogger::getInstance()->getLogCoutProcessId()     //进程宏
    #define __FDOGTID__   FdogLogger::getInstance()->getLogCoutThreadId()      //线程宏
    #define __FDOGFILE__  __FILE__        //文件名宏
    #define __FDOGPASH__  FdogLogger::getInstance()->getFilePash() + __FDOGFILE__ //文件路径
    #define __FDOGFUNC__   __func__        //函数名宏
    #define __FDOGLINE__  __LINE__        //行数宏
    #define __USERNAME__  FdogLogger::getInstance()->getLogCoutUserName()     //获取调用用户名字
    #define __FDOGNAME__(name) #name        //名字宏
    
    
    #define COMBINATION_INFO_FILE(coutTypeInfo, message) \
        do{\
            string messagesAll = __FDOGTIME__ + coutTypeInfo + __USERNAME__ + __FDOGTID__ + SQUARE_BRACKETS_LEFT + \
            __FDOGPASH__  + SPACE +__FDOGFUNC__ + COLON + to_string(__FDOGLINE__) + SQUARE_BRACKETS_RIGHT + message + LINE_FEED;\
            FdogLogger::getInstance()->logFileWrite(messagesAll); \
        }while(0);
    
    #define COMBINATION_INFO_TERMINAL(coutTypeInfo, message) \
        do{\
            string messagesAll = __FDOGTIME__ + WHITE + coutTypeInfo + DEFA + __USERNAME__ + __FDOGTID__ + SQUARE_BRACKETS_LEFT + \
            __FDOGPASH__  + SPACE +__FDOGFUNC__ + COLON + to_string(__FDOGLINE__) + SQUARE_BRACKETS_RIGHT + message + LINE_FEED;\
            cout << messagesAll;\
        }while(0);
    
    #define LoggerCout(coutTyle, coutTypeInfo, fileCoutBool, terminalCoutBool, message) \
        do {\
            string coutType = FdogLogger::getInstance()->getCoutType(coutTyle);\
            if (FdogLogger::getInstance()->getFileType(fileCoutBool)) {\
                COMBINATION_INFO_FILE(coutTypeInfo, message)\
            }\
            if (FdogLogger::getInstance()->getTerminalType(terminalCoutBool)) {\
                COMBINATION_INFO_TERMINAL(coutTypeInfo, message)\
            }\
        }while(0);
    
    #define FdogError(message) \
        do{\
            LoggerCout(fdog::coutType::Error, Error1, fdog::fileType::Error, fdog::terminalType::Error, message)\
        }while(0);
    
    #define FdogWarn(message)  \
        do{\
            LoggerCout(fdog::coutType::Warn, Warn1, fdog::fileType::Warn, fdog::terminalType::Warn, message)\
        }while(0);
    
    #define FdogInfo(message)  \
        do{\
            LoggerCout(fdog::coutType::Info, Info1, fdog::fileType::Info, fdog::terminalType::Info, message)\
        }while(0);
    
    #define FdogDebug(message) \
        do{\
            LoggerCout(fdog::coutType::Debug, Debug1, fdog::fileType::Debug, fdog::terminalType::Debug, message)\
        }while(0);
    
    #define FdogTrace(message) \
        do{\
            LoggerCout(fdog::coutType::Trace, Trace1, fdog::fileType::Trace, fdog::terminalType::Trace, message)\
        }while(0);
    
    }
    
    #endif
    
    
    2. fdoglogger.cpp
    #include"fdoglogger.h"
    
    using namespace fdog;
    
    
    FdogLogger * FdogLogger::singleObject = nullptr;
    mutex * FdogLogger::mutex_new = new(mutex);
    
    FdogLogger::FdogLogger(){
        initLogConfig();
    }
    FdogLogger::~FdogLogger(){
    
    }
    
    FdogLogger* FdogLogger::getInstance(){
        mutex_new->lock();
        if (singleObject == nullptr) {
            singleObject = new FdogLogger();
        }
        mutex_new->unlock();
        return singleObject;
    }
    
    void FdogLogger::initLogConfig(){
    
        map<string, string *> flogConfInfo;
        flogConfInfo["logSwitch"] = &this->logger.logSwitch;
        flogConfInfo["logFileSwitch"] = &this->logger.logFileSwitch;
        flogConfInfo["logTerminalSwitch"] = &this->logger.logTerminalSwitch;
        flogConfInfo["logName"] = &this->logger.logName;
        flogConfInfo["logFilePath"] = &this->logger.logFilePath;
        flogConfInfo["logMixSize"] = &this->logger.logMixSize;
        flogConfInfo["logBehavior"] = &this->logger.logBehavior;
        flogConfInfo["logOverlay"] = &this->logger.logOverlay;
        flogConfInfo["logOutputLevelFile"] = &this->logger.logOutputLevelFile;
        flogConfInfo["logOutputLevelTerminal"] = &this->logger.logOutputLevelTerminal;
    
        string str;
        ifstream file;
        char str_c[100]={0};
        file.open("fdoglogconf.conf");
        if(!file.is_open()){
            cout<<"文件打开失败\n";
        }
        while(getline(file, str)){
            if(!str.length()) {
                continue;
            }
            string str_copy = str;
            //cout<<"获取数据:"<<str_copy<<endl;
            int j = 0;
            for(int i = 0; i < str.length(); i++){
                if(str[i]==' ')continue;
                str_copy[j] = str[i];
                j++;
            }
            str_copy.erase(j);
            if(str_copy[0]!='#'){
                sscanf(str_copy.data(),"%[^=]",str_c);
                auto iter = flogConfInfo.find(str_c);
                if(iter!=flogConfInfo.end()){
                    sscanf(str_copy.data(),"%*[^=]=%s",str_c);
                    *iter->second = str_c;
                } else {
                }
            }
        }
        logger.logName = logger.logName + getLogNameTime() + ".log";
    
        bindFileCoutMap("5", fileType::Error);
        bindFileCoutMap("4", fileType::Warn);
        bindFileCoutMap("3", fileType::Info);
        bindFileCoutMap("2", fileType::Debug);
        bindFileCoutMap("1", fileType::Trace);
    
        bindTerminalCoutMap("5", terminalType::Error);
        bindTerminalCoutMap("4", terminalType::Warn);
        bindTerminalCoutMap("3", terminalType::Info);
        bindTerminalCoutMap("2", terminalType::Debug);
        bindTerminalCoutMap("1", terminalType::Trace);
    
        if(logger.logFileSwitch == "on"){
            if(!createFile(logger.logFilePath)){
                std::cout<<"Log work path creation failed\n";
            }
        }
    
        cout << "|========FdogLogger v2.0==========================|" <<endl << endl;
        cout << "  日志开关:" << logger.logSwitch << endl;
        cout << "  文件输出:" << logger.logFileSwitch << endl;
        cout << "  终端输出:" << logger.logTerminalSwitch << endl;
        cout << "  日志输出等级(文件):" << logger.logOutputLevelFile << endl;    
        cout << "  日志输出等级(终端):" << logger.logOutputLevelTerminal << endl;
        cout << "  日志文件名:" << logger.logName << endl;
        cout << "  日志保存路径:" << logger.logFilePath << endl;
        cout << "  单文件最大大小:"<< logger.logMixSize << "M" << endl;
        cout << "  日志保存时间 :" << logger.logOverlay << "天" << endl << endl;
        cout << "|=================================================|" <<endl;
        
        return;
    }
    
    string FdogLogger::getCoutType(coutType coutType){
        return singleObject->coutTypeMap[coutType];
    }
    
    bool FdogLogger::getFileType(fileType fileCoutBool){
        return singleObject->fileCoutMap[fileCoutBool];
    }
    
    bool FdogLogger::getTerminalType(terminalType terminalCoutTyle){
        return singleObject->terminalCoutMap[terminalCoutTyle];
    }
    
    string FdogLogger::getLogCoutTime(){
        time_t timep;
        time (&timep);
        char tmp[64];
        strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S",localtime(&timep));
        string tmp_str = tmp;
    
        return SQUARE_BRACKETS_LEFT + tmp_str + SQUARE_BRACKETS_RIGHT;
    }
    
    string FdogLogger::getLogNameTime(){
        time_t timep;
        time (&timep);
        char tmp[64];
        strftime(tmp, sizeof(tmp), "%Y-%m-%d-%H:%M:%S",localtime(&timep));
        return tmp;
    }
    
    string FdogLogger::getFilePash(){
        getcwd(szbuf, sizeof(szbuf)-1);
        string szbuf_str = szbuf;
        return szbuf_str + SLASH;
    }
    
    string FdogLogger::getLogCoutProcessId(){
    #ifndef linux
        return to_string(getpid());
    #endif
    #ifndef WIN32
    //  unsigned long GetPid(){
    //     return GetCurrentProcessId();
    // }
    #endif
    }
    
    string FdogLogger::getLogCoutThreadId(){
    #ifndef linux
        return to_string(syscall(__NR_gettid));
    #endif
    #ifndef WIN32
    //  unsigned long GetTid(){
    //     return GetCurrentThreadId();
    // }
    #endif
    }
    
    string FdogLogger::getLogCoutUserName(){
        struct passwd *my_info;
        my_info = getpwuid(getuid());
        string name = my_info->pw_name;
        return SPACE + name + SPACE;
    }
    
    bool FdogLogger::createFile(string filePash){
        int len = filePash.length();
        if(!len){
            filePash = "log";
            if (0 != access(filePash.c_str(), 0)){
                if(-1 == mkdir(filePash.c_str(),0)){
                    std::cout<<"没路径";
                    return 0;
                }
            }
        }
        std::string filePash_cy(len,'\0');
        for(int i =0;i<len;i++){
            filePash_cy[i]=filePash[i];
            if(filePash_cy[i]=='/' || filePash_cy[i]=='\\'){
                if (-1 == access(filePash_cy.c_str(), 0)){
                    if(0!=mkdir(filePash_cy.c_str(),0)){
                        std::cout<<"有路径";
                        return 0;
                    }
                }
            }
        }
        return 1;
    }
    
    bool FdogLogger::logFileWrite(string messages){
        ofstream file;
        file.open(logger.logFilePath + logger.logName, ::ios::app | ios::out);
        if(!file){
            cout<<"写失败"<<endl;
            return 0;
        }
        file << messages;
        file.close();
        return 1;
    }
    
    bool FdogLogger::bindFileCoutMap(string value1, fileType value2){
        if(logger.logOutputLevelFile.find(value1)!=std::string::npos) {
            fileCoutMap[value2] = true;
        } else {
            fileCoutMap[value2] = false;
        }
    }
    
    bool FdogLogger::bindTerminalCoutMap(string value1, terminalType value2){
        if(logger.logOutputLevelTerminal.find(value1)!=std::string::npos) {
            terminalCoutMap[value2] = true;
        } else {
            terminalCoutMap[value2] = false;
        }
    }
    

    四. 测试用例

    在这里插入图片描述

    1. fdoglogger_test.cpp
    #include<iostream>
    #include"fdoglogger.h"  //添加日志库头文件
    
    using namespace fdog;   //日志库的命名空间
    
    int main(){
        FdogError("错误");
        FdogWarn("警告");
        FdogInfo("信息");
        FdogDebug("调试");
        FdogTrace("追踪");
        return 0;
    }
    

    在这里插入图片描述

    在这里插入图片描述

    暂时考虑到的就是这些,如有缺陷,欢迎评论区补充。(比如文件写入打开就关闭,很浪费资源,如何优化,下篇见)。

    源码已上传github,还原star! FdogLog,一个轻量级C++日志库,用于日志服务。


    展开全文
  • 对于程序员, 每一个程序都要有一个的日志系统, 这是我之前用过的, 感觉还不是错, 就二个文件。 便实现了很写日志功能。 分享给大家 。
  • C# 写日志

    千次阅读 2018-03-16 09:25:04
    新建一个C# Windows窗口应用程序。 ... 把这个文件添加到工程的引用中。...5.把C_LogWriter.cs复制到工程中,然后添加工程中的现有项中。 修改名称空间,方便其他类中进行调用。C#中的每个.cs文件都是一...
    1. 新建一个C# Windows窗口应用程序。
    2. log4net.dll 放在工程文件夹里。
      这里写图片描述
      把这个文件添加到工程的引用中。
      这里写图片描述
      3.在项目名称上右键点击属性,选择相应的目标框架。
      这里写图片描述
      4.修改App.config文件,把之前的替换掉。
      5.把C_LogWriter.cs复制到工程中,然后添加在工程中的现有项中。
      这里写图片描述
      这里写图片描述
      修改名称空间,方便在其他类中进行调用。C#中的每个.cs文件都是一个类。所以有一个统一的名称空间就很好使用。
      这里写图片描述
      6.在窗口的类中添加
      public static C_LogWriter log = new C_LogWriter();
      定义一个全局变量来实例化这个类。
      7.接下来可以通过写一个按键程序测试一下日志,通过按下按键来把一句话写入到日志中。
      接下来进入按键按下事件中,添加一些话,这些都会写入到log中。
      这里写图片描述
      8.运行程序,按下几次按键。
      在Log\LogTest\LogTest\bin\Debug\Log\CommLog路径下会保存一个log记事本,打开可以查看内容。
      这里写图片描述
      说明测试成功了。
      可以看出时间精确到了1ms的级别,所以通过日志来调试程序很方便。

    相关源码请到下面的github地址下载:
    https://github.com/MRwangmaomao/Log-Project.git

    展开全文
  • 经常想为程序添加写日志的功能,但一想到要...现在了,我想了个办法,一个语句就可以完成写日志的功能了。再也不用为该不该花时间做日志功能这个问题纠结了,想写就写,简单得很。大家下载来看看吧。给我个好评哦!
  • 现在很多企业和公司都有工作日志的习惯,既是领导检查工作和绩效考核的需要,也是自己工作中成长学习的一种习惯。此文档遵循PDCA原则,简单实用,不求完美,但求每日进益,每天精进。
  • 如何优雅的写日志

    千次阅读 2018-02-27 11:02:08
    前言代码中编写日志是日常开发中的基本要求,记录日志一方面是方便日后通过日志能够查找问题原因,另一方面也可以用于后续的审计工作。我以前对团队编写日志的要求是,通过打印的日志就可以看出整个代码的业务逻辑...

    前言

    在代码中编写日志是日常开发中的基本要求,记录日志一方面是方便日后通过日志能够查找问题原因,另一方面也可以用于后续的审计工作。我以前对团队编写日志的要求是,通过打印的日志就可以看出整个代码的业务逻辑,所以我们团队的代码可以做到没有注释,通过代码中的日志就可以了解到整个代码的业务逻辑。这样要求的好处是看日志查问题的时候,通过看日志就知道代码的处理逻辑,而不用再翻出代码来看业务处理逻辑了。我相信很多同学都有类似的感受,就是在查日志的时候发现日志的信息都非常的混乱,查起问题来别提多别扭了,如果日志都按业务逻辑记录好了那就不会存在这样的问题。

    1. 日志要求

    我们在代码中记录日志从大类上区分,一般有两种,一种是所有交易都记录的系统基础日志,日志中会包含系统时间、请求返回报文、用户名等等信息;还有一种是业务相关的逻辑日志。

    1.1 日志分级

    我们先来说下大家记录的最多的业务逻辑日志,记录逻辑日志我们一般都会对日志进行分级error、info、debug这些级别,因为日志记录的太详细就会影响到服务器性能,所以一般我们在生产上只会打开info级别的,有的交易量比较大的系统甚至只打开error级别的日志。

    1.2 逻辑日志记录

    开头说了对于info或者debug级别的日志,需要能够在代码中明确写出,在每个代码分支的地方都记录分支条件的日志,这样当出现问题后通过查看日志就能够知道为什么走到的错误的分支,直接看日志就知道出异常时候每一步关键参数的值,如果逻辑日志记录的完整的话,查问题甚至都不需要在ide中进行debug。

    例:在每个分支都记录逻辑日志,这样方便在日志中查找到问题根因

    private boolean initEngine(){
            logger.info("init all engines begin: ");
            Map<String, IEngine> engines = commonEngineFactory.getAllEngines();
            Map<String, IEngine> customEngines = customEngineFactory.getAllEngines();
            if(customEngines == null && engines == null){
                logger.info("customEngines == null && engines == null.");
                return false;
            }else if(customEngines != null) {
                engines.putAll(customEngines);
            }
            CloudAppContext.getInstance().setEngineMap(engines);
            logger.info("init engines = " + engines);
            return true;
        }
    

    1.3 切面纪录系统日志

    对于系统日志我们一般采取的是通过切面进行日志记录,这样可以最大限度的减少日志对系统逻辑的影响,再通过自定义注解可以在需要加系统日志的逻辑类方法前面加上系统切面注解就可以。下面的章节我们详细讲解下如何实现切面日志。

    2. 切面日志实现

    为了实现上面说到的切面日志,需要实现下面几个东西,首先要定义一个自定义环绕注解,第二要定义一个Aspect类来重写环绕注解方法,最后还要自定义一个写日志接口,并实现这个接口。下面分别介绍下具体实现方式。

    实现完注解切面日志相关类后,可以在相关业务类的逻辑方法前加上方法环绕注解@SysLog,这样就实现了环绕注解,对业务逻辑代码完全没有侵入性。

        /**
         * 保存配置
         */
        @SysLog("保存配置")
        @RequestMapping("/save")
        public ResponseBean save(@RequestBody SysConfigEntity config){
            ValidatorUtils.validateEntity(config);
    
            sysConfigService.save(config);
            
            return ResponseBean.ok();
        }
    

    2.1 环绕注解

    自定义一个SysLog的注解类,方便在其他逻辑类里使用,这样逻辑代码就不用在逻辑代码中加入这种通用系统日志,在逻辑代码中将只存在业务日志。

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SysLog {
    
        String value() default "";
    }
    

    在切面类中重写环绕注解,around方法的point入参就是需要进行代理的业务类的切入点,调用point.proceed()就会代理调用加了@SysLog注解的业务方法,在这个业务方法前后我们可以加上我们要记录的任何系统日志信息。

    @Around("logPointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            long beginTime = System.currentTimeMillis();
            //执行业务逻辑方法
            Object result = point.proceed();
            //执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
    
            //保存日志
            saveSysLog(point, time);
    
            return result;
        }
    

    2.2 日志切面

    上面定义了自定义注解,为了实现切面日志,当然需要定义一个切面类,不然系统是无法知道在哪里形成切面,并在切面之前还是之后进行切面方法操作,Aspect的底层实现,其实就是一个动态代理,jvm启动的时候会找寻到相关切面注解,然后在业务类的基础上又定义了一个包含切面相关方法的动态代理类,在执行的时候会先调用到这个动态代理类,执行切面中的方法,再执行业务逻辑方法。

    @Aspect
    @Component
    public class SysLogAspect {
        @Autowired
        private SysLogService sysLogService;
        //定义切入点Pointcut
        @Pointcut("@annotation(com.monkey01.log.aspect.SysLog)")
        public void logPointCut() { 
            
        }
    
        @Around("logPointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            long beginTime = System.currentTimeMillis();
            //执行业务逻辑方法
            Object result = point.proceed();
            //执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
    
            //保存日志
            saveSysLog(point, time);
    
            return result;
        }
    
        private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
    
            SysLogEntity sysLog = new SysLogEntity();
            SysLog syslog = method.getAnnotation(SysLog.class);
            if(syslog != null){
                //注解上的描述
                sysLog.setOperation(syslog.value());
            }
    
            //请求的方法名
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = signature.getName();
            sysLog.setMethod(className + "." + methodName + "()");
    
            //请求的参数
            Object[] args = joinPoint.getArgs();
            try{
                String params = new Gson().toJson(args[0]);
                sysLog.setParams(params);
            }catch (Exception e){
    
            }
    
            sysLog.setTime(time);
            sysLog.setCreateDate(new Date());
            //保存系统日志
            sysLogService.save(sysLog);
        }
    }
    

    定义一个系统日志实体类,方便日后对系统日志统一格式化。

    public class SysLogEntity implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private Long id;
        //用户名
        private String username;
        //用户操作
        private String operation;
        //请求方法
        private String method;
        //请求参数
        private String params;
        //执行时长(毫秒)
        private Long time;
        //IP地址
        private String ip;
        //创建时间
        private Date createDate;
    
        /**
         * 设置:
         */
        public void setId(Long id) {
            this.id = id;
        }
        /**
         * 获取:
         */
        public Long getId() {
            return id;
        }
        /**
         * 设置:用户名
         */
        public void setUsername(String username) {
            this.username = username;
        }
        /**
         * 获取:用户名
         */
        public String getUsername() {
            return username;
        }
        /**
         * 设置:用户操作
         */
        public void setOperation(String operation) {
            this.operation = operation;
        }
        /**
         * 获取:用户操作
         */
        public String getOperation() {
            return operation;
        }
        /**
         * 设置:请求方法
         */
        public void setMethod(String method) {
            this.method = method;
        }
        /**
         * 获取:请求方法
         */
        public String getMethod() {
            return method;
        }
        /**
         * 设置:请求参数
         */
        public void setParams(String params) {
            this.params = params;
        }
        /**
         * 获取:请求参数
         */
        public String getParams() {
            return params;
        }
        /**
         * 设置:IP地址
         */
        public void setIp(String ip) {
            this.ip = ip;
        }
        /**
         * 获取:IP地址
         */
        public String getIp() {
            return ip;
        }
        /**
         * 设置:创建时间
         */
        public void setCreateDate(Date createDate) {
            this.createDate = createDate;
        }
        /**
         * 获取:创建时间
         */
        public Date getCreateDate() {
            return createDate;
        }
    
        public Long getTime() {
            return time;
        }
    
        public void setTime(Long time) {
            this.time = time;
        }
    
        @Override
        public String toString() {
            return "SysLogEntity{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", operation='" + operation + '\'' +
                    ", method='" + method + '\'' +
                    ", params='" + params + '\'' +
                    ", time=" + time +
                    ", ip='" + ip + '\'' +
                    ", createDate=" + createDate +
                    '}';
        }
    }
    

    2.3 日志服务封装

    很多人会问上面注解和切面类都写好了不就可以直接使用了吗?但是我们要知道写日志的具体实现和方式可能会不断改变,例如之前我们都是使用log4j突然架构师说logback性能更好,要全换了,或者是我们原来都是记录本地文件日志,突然有要求都发送到中央日志中心,是不是一下就懵逼了,所以我们要定义一个写日志的服务接口,在所有要调用业务日志系统日志写入的地方都调用这个接口实现,而不是直接调用具体的日志实现,做一个接口隔离,这样后面的实现我们可以很轻松的随意改变而不会影响到业务逻辑代码。

    @Service
    public interface SysLogService {
        void save(SysLogEntity sysLog);
    }
    

    这个实现可以是简单的直接本地打印,也可以是写数据库,也可以是调用logback这些写本地文件,甚至是直接网络发送到中央日志中心。

    @Service("sysLogService")
    public class SysLogServiceImpl implements SysLogService {
        @Override
        public void save(SysLogEntity sysLog){
    //      sysLogDao.saveSysLog(sysLog);
            System.out.println(sysLog);
        }
    
    }
    

    3. 提高日志性能

    3.1 设置缓存并异步写日志

    log4j缓存配置,因为磁盘1个block为8k,配置为达到8k写一次日志文件。

    <appender name="monitorAppender"
              class="org.apache.log4j.DailyRollingFileAppender">
      <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%m%n" />
      </layout>
      <param name="DatePattern" value="'.'yyyy-MM-dd-HH" />        
      <param name="File" value="mtlogs/mt_log.txt" />
      <param name="BufferedIO" value="true" />
      <!-- 8K为一个写单元 -->
      <param name="BufferSize" value="8192" />
    </appender>
    
    <appender name="ASYNCOUT" class="org.apache.log4j.AsyncAppender">    
         <param name="BufferSize" value="512" />    
       <appender-ref ref="DRFOUT" />    
     </appender> 
    

    logback设置异步队列

    <appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">  
      <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->  
      <discardingThreshold >0</discardingThreshold>  
      <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->  
      <queueSize>512</queueSize>  
      <!-- 添加附加的appender,最多只能添加一个 -->  
      <appender-ref ref ="FILE"/>  
    </appender> 
    

    log4j和logback异步记录日志的原理基本是一样的,都是采用了异步队列的方式,先将要记录的日志直接poush到本地的BlockingQueue中,当queue中的日志量达到设置的buffer阈值的时候再启动一个异步线程获取queue中待写入的日志去写本地文件。因为磁盘io的成本是非常高的,所以每次异步写日志的时候,最好是磁盘block的整数倍,这样能够充分利用磁盘IO,不会造成写资源浪费。

    3.2 异步发送网络日志

    本地日志是一种方式,但是最近几年,大部分互联网公司都在公司内部建立中央集群日志类似ELK之类。这类中央日志的好处有很多,一个是方便集群量比较大的系统去查日志,现在互联网系统大部分都有很多集群节点,笔者之前做过一个移动端应用服务系统,有36个节点,当有这么多节点的时候,最痛苦的有两件事,一件事是上每个节点查询日志,还有一件是版本部署,多节点日志查询可以通过中央日志系统来解决,多节点版本部署可以通过docker之类的容器化技术或者自动化部署来解决;中央日志第二个好处是减少每个内部系统的日志压力,每个系统不用写到本地日志文件,占用本地磁盘空间,拖慢交易。

    通过异步发送网络日志一般来说能够大幅提高日志性能,系统只需要每次将要写的日志发送到队列中,再从队列取出日志批量发送到中央日志系统。

    上面介绍了下我们写日志比较好的实践,希望大家能够应用到自己的项目中,降低日志对系统逻辑代码的耦合性。



    作者:monkey01
    链接:https://www.jianshu.com/p/e02ea3256f71
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    展开全文
  • 写日志的那些事儿

    千次阅读 2016-01-30 14:36:37
    摘要写日志简介 一般提到写日志,主要有下面几种不同的场景: 诊断日志:应用打印异常信息,排查问题用,一般是给人看的,输出格式会比较随意,里面可能会有异常堆栈,或者排查问题用的一些文本信息; 数据日志:...
  • 然后我们先主对象树里面设置db连接 测试一下 就可以继续了。 里面有各种数据库的连接类型 根据自己的需求 选择数据库连接 配置之后 我们就开始kettle脚本 (里面具体的sql脚本就可以) 现在核心...
  • 系统日志数据库还是文件 http://bbs.csdn.net/topics/391955508?page=1 http://bbs.csdn.net/topics/370239356 文件需要注意 高并发的写入问题和锁问题。 数据库注意开销。 ...
  • 多线程下写日志

    万次阅读 2014-10-31 17:00:21
    鄙人最近遇到了一个奇特的线上事故,记录一下,以备记忆。  鄙人所在的部门负责给公司提供各种基础库,即基础架构部门。最近某别的部门用本部门提供的支持多线程版本的日志库后,...先说下这个日志库的写日志过程,
  • (因为不同的位置,不同的线程调用LOGIN写日志时,行号什么的都会不同,如果硬要和MyLog整个日志库捆绑到一起的话,就不可避免的需要使用互斥锁,一个线程写日志的时候,需要改变行号等临时信息,其他线程需要阻塞...
  • 公司更新项目功能更新的时候本来五分钟...而且也不会去写日志,然后我以为是日志写的太多了十几个G的日志了,把日志全部干掉之后还是不行,最终百度找到一个解决方法,不去使用start.sh启动,使用"./catal...
  • 对redo log、binlog这种日志进行的磁盘顺序读写 对表空间的磁盘文件里的数据页进行的磁盘随机读写 1 磁盘随机读 MySQL执行增删改操作时,先从表空间的磁盘文件里读数据页出来, 这就是磁盘随机读。 如下图有个磁盘...
  • 程序员如何工作日志

    万次阅读 2018-11-06 09:09:42
    每到周总结的时候,已经忘记本周做了哪些工作,为了防止这种情况,强烈建议养成日志习惯!工作日志的内容不限,可参考下面的模板 计划 当天的工作计划 ,具体到可以完成的一个很小的任务 学习 工作中接触的新...
  • 轻轻松松教你写日志-超级简单

    千次阅读 热门讨论 2015-08-12 23:31:01
    直接写日志,一步定位哪里出了错。 Log4Net库是一个帮助程序员将日志信息输出到各种目标(控制台、文件 数据库等)的工具。  Log4Net,相信哪个程序员都用过,但是可能是人家配置了自己拿过来直接用,所以让自己写...
  • linux中怎么查看错误日志

    千次阅读 2021-05-11 22:44:59
    cat或者tail -f命令日 志 文 件 说 明/var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日志之一/var/log/secure 与安全相关的日志信息/var/log/maillog 与邮件相关的日志信息/var/log/cron ...
  • 日志(Write-Ahead Logging (WAL))

    千次阅读 2018-05-24 19:44:07
    日志 (WAL) 是一种实现事务日志的标准方法。有关它的详细描述可以大多数(如果不是全部的话)有关事务处理的书中找到。 简而言之,WAL 的中心思想是对数据文件的修改(它们是表和索引的载体)必须是只能...
  • Log4j2写日志的艺术

    千次阅读 2017-06-26 21:01:53
    写日志的原理 主要流程 同步写 异步写 顺便说一下ArrayBlockingQueue notFull 与 notEmpty 异步写是怎么玩的 巧妙的异步写设计 ByteBuffer与RandomAccessFile Garbage-free避免创建多余对象 异步Logger 性能 写...
  • 引言: 日志大家都再熟悉不过了,日常开发...就我进行心里斗争的时候,接口人又说了“什么时候能定位到问题,啥时候能解决?”。(甲方规定:超1小时通报、超过2小时扣分、超4小时约谈领导、24小时没搞定打包回家)
  • 使用Log4j.jar写日志到文件

    千次阅读 2016-04-15 08:44:08
    log4j.jar文件log4j.jar是用来写日志的高效的一个工具, 网上下载log4j.jar包 放在工程中,我的是Myeclipse中的JavaWeb工程 具体目录,不固定,可以是src,或是新建一个文件夹都可以 新建一个log4j.properities...
  • 对于这部分 CPU IO 上的开销,我们称为 “iowait”。 iowait 怎么查看呢? 如果你用的是 Linux 系统或者 Mac 系统,当你执行一项很耗费磁盘 IO 的操作时,比如读写大文件,通过 top 命令便可以看到。如下图所示...
  • 写日志方法的改进

    2014-06-17 17:19:47
    最近了个程序,需要记录日志
  • 如何代码中打日志

    千次阅读 2019-02-24 02:59:32
    之前对于代码中的console.log一直是比较嫌弃的,以致于提交代码前一般会通过eslint检测是否包含了log输出。 最近一直处理一个chrome插件的需求,需要打开某个url标签页,然后根据预先设定的操作行为,页面上进行...
  • js 程序日志代码

    千次阅读 2014-11-26 11:04:15
    //一行,并使文件结尾跳到新的一行 tf.WriteLine(sWrite); //文件结尾当前行的下一行开头处。 tf.Write(""); //文件结尾就当前行的最后一个字符后面 tf.Close(); //关闭文件 } ...
  • 就是记录一个用户页面上的修改操作 记录到日志中或者文件中 又怎么读取修改之前和修改之后的值,然后显示页面上,本人小白 有那位大哥大姐 不吝赐教 有什么的列子借鉴一下的 小弟拜谢了
  • nginx日志切割shell脚本

    2020-09-15 20:24:54
    nginx的日志文件没有rotate功能。如果你不处理,日志文件将变得越来越大,还我们可以一个nginx日志切割脚本来自动切割日志文件

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 676,365
精华内容 270,546
关键字:

在哪里写日志比较好