【项目实战】自主实现 HTTP 项目(二)——日志的打印与添加

目录

打印日志

日志的作用

一个简单的测试

日志的结构

时间戳:

日志编写 

添加日志信息

tcp文件添加日志

http文件添加日志

Protocol文件添加日志

日志测试


打印日志

日志的作用

什么是日志呢,简单来说就是反映项目中的执行过程阶段性结果的一种信息获取。

我们之前是通过自己定义直接输出打印某步骤中执行的结果,如下面的代码:

if (_sock < 0){
std::cerr << "socket error" << std::endl;
exit(2);
}

这是我们自己"socket error" 输出的,而了解过网络编程的类似绑定,监听,以及各种执行下来,这种结构不在少数,难道都我们自己来一个一个把他们写出来吗,肯定不是的,我们可以设置一个日志信息,当执行到某一部的时候,把相关性质的参数传给它,让他帮我们快捷性的打印当前的执行结果状态,这就是日志的作用。

一个简单的测试

在之前的C语言中,我们想要打印对应的行列信息,我们可以用到C语言给我们的预定义的宏,而在这里我们其实就可以用到它,我们先来做一个简单测测试。

编译链接通过,我们可以看到

 就成功打印了我们的文件名和行号

日志的结构

 【说明】:

日志级别 :

· 公有四种级别,分别是 INFO(执行正常)、 WARNING (有警告)  、ERROR   (执行中遇到错误)FATAL (执行极端),注意INFO是正常执行,而FATAL级别一般是表示程序几乎已经崩溃,这个时候不能再让程序执行下去了,必须终止。

日志信息:详细说明这一步的情况内容。

错误行:这里表示当前错误的行数,上面的测试验证了我们可以直接用C中的宏。

错误文件信息:表示文件出错内容的详细信息。

时间戳:

我们在刚刚开始学习Linux时间戳的时候,学习一些常见的命令,但是我们这里暂时不用,我们还是用time的时间戳。

 我们不需要知道实际的时间,我们只要让其起到时间戳最原本的目的,数值随着时间的变化而变化就可以了,我们可以来一个简单的时间戳的测试

 我们编译链接,查看一下时间戳的具体情况:

我们可以看到,这里起到了我们想要查看的时间戳的效果。

日志编写 

#pragma once

#include <iostream>
#include <string>
#include <ctime>

#define INFO    1
#define WARNING 2
#define ERROR   3
#define FATAL   4

#define LOG(level, message) Log(#level, message, __FILE__, __LINE__)

void Log(std::string level, std::string message, std::string file_name, int line)
{
    std::cout << "[" << level << "]" << "[" << time(nullptr) << "]" << "[" << message << "]" << "[" << file_name << "]" << "[" << line << "]" << std::endl;
}

 说明:我们把level级别定义成了宏,但是我们传入级别的时候,却是以字符串的形式传入的,这个时候我们应该再定义一个宏,把参数设置成#level可以把整数转化成字符串的形式。

添加日志信息

tcp文件添加日志

#pragma once

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "Log.hpp"

#define BACKLOG 5

class TcpServer{
    private:
        int port;
        int listen_sock;
        static TcpServer *svr;
    private:
        TcpServer(int _port):port(_port),listen_sock(-1)
        {}
        TcpServer(const TcpServer &s){}
    public:
        static TcpServer *getinstance(int port)
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
            if(nullptr == svr){
                pthread_mutex_lock(&lock);
                if(nullptr == svr){
                    svr = new TcpServer(port);
                    svr->InitServer();
                }
                pthread_mutex_unlock(&lock);
            }
            return svr;
        }
        void InitServer()
        {
            Socket();
            Bind();
            Listen();
            LOG(INFO, "tcp_server init ... success");
        }
        void Socket()
        {
            listen_sock = socket(AF_INET, SOCK_STREAM, 0);
            if(listen_sock < 0){
                LOG(FATAL, "socket error!");
                exit(1);
            }
            int opt = 1;
            setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
            LOG(INFO, "create socket ... success");
        }
        void Bind()
        {
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(port);
            local.sin_addr.s_addr = INADDR_ANY; //云服务器不能直接绑定公网IP

            if(bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){
                LOG(FATAL, "bind error!");
                exit(2);
            }
            LOG(INFO, "bind socket ... success");
        }
        void Listen()
        {
            if(listen(listen_sock, BACKLOG) < 0){
                LOG(FATAL, "listen socket error!");
                exit(3);
            }
            LOG(INFO, "listen socket ... success");
        }
        int Sock()
        {
            return listen_sock;
        }
        ~TcpServer()
        {
            if(listen_sock >= 0) close(listen_sock);
        }
};

TcpServer* TcpServer::svr = nullptr;

【说明】:我们是根据所处的状态进行等级的划分,像是创建套件字失败,绑定失败,监听失败等,需要立即停止进程,这个时候应当把等级设置为极限FATAL,程序正常情况下设置为INFO即可

http文件添加日志

#pragma once 

#include <iostream>
#include <pthread.h>
#include"Protocol.hpp"
#include "TcpServer.hpp"
#include"Log.hpp"

#define PORT 8081

class HttpServer{
private:
    int port;
    TcpServer *tcp_server;
    bool stop;
public:
    HttpServer(int _port = PORT):port(_port),tcp_server(nullptr),stop(false)
    {}
    
    void InitServer()
    {
      tcp_server =TcpServer::getinstance(port);
    }
     
    void Loop()
    {
      LOG(INFO,"Loop,begin!");
      int listen_sock = tcp_server->Sock();
      while(!stop){
        struct sockaddr_in peer;
        socklen_t len =sizeof(peer);
        int sock =accept(listen_sock,(struct sockaddr*)&peer,&len);
        if(sock < 0 ){
          continue;
        }
        LOG(INFO,"Get a new link");
        int *_sock = new int(sock);
        pthread_t tid;
        pthread_create(&tid,nullptr,Entrance:: HandlerRequest,_sock);
        pthread_detach(tid);

        

      }
    }
    
    
    ~HttpServer()
    {}
};

Protocol文件添加日志

class Entrance{
    public:
      static void *HandlerRequest(void *_sock)
      {
        LOG(INFO,"Hander Requeset Begin!");
        int sock =*(int*)_sock;
        delete (int*)_sock;  
       
 
#ifdef DEBUG 
        //For Test
          char buffer[4096];
          recv(sock,buffer,sizeof(buffer),0);
          std::cout<<"-------------------begin--------------------"<<std::endl;
          std::cout<<buffer<<std::endl;
          std::cout<<"-------------------end--------------------"<<std::endl;
      
#else 
          EndPoint *ep = new EndPoint(sock);
          ep->RecvHttpPoint();
          ep->ParseHttpRequest();
          ep->BuildHttpResponse();
          ep->SendHttpResponse();
          delete ep;
#endif 
         LOG(INFO,"Hander Request End!");
          return nullptr;

      }

};

日志测试

我们把日志添加到文件当中之后,我们就可以对日志进行简单的测试,编译完成通过,我们运行一下,如下图所示:

这个时候我们看到日志信息打印了我们一步一步的正常流程,我们现在通过浏览器,对其进行一下访问,我们可以看到的是如下:

 

我们看到了链接的日志信息,以及其处理方法的日志信息,并打印到了我们的显示器上。

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值