【负载均衡在线OJ项目日记】编译与日志功能开发

ops/2025/2/12 10:37:29/

目录

日志功能开发

常见的日志等级

日志功能代码

编译功能开发

创建子进程和程序替换

重定向

编译功能代码


日志功能开发

日志在软件开发和运维中起着至关重要的作用,目前我们不谈运维只谈软件开发;日志最大的作用就是用于故障排查和调试;

当系统出现问题时,日志记录可以帮助开发人员追踪问题的根源。通过查看日志文件,开发人员可以了解系统在发生故障之前的行为,识别错误发生的时间、地点和原因,并快速定位到错误的代码或功能模块。

因此我们要为目前这个项目编写一个简单的日志模块,这个模块可能被项目中的任何一个部分使用,我们将其放在公共模块的一个文件中。

常见的日志等级

  1. DEBUG(调试): 用于记录程序的详细运行信息,通常用于开发和调试阶段,帮助开发人员定位问题和追踪程序流程。

  2. INFO(信息): 用于记录程序正常运行时的重要信息,例如启动信息、关键操作记录等,可用于了解系统的基本运行情况。

  3. WARNING(警告): 用于记录一些潜在的问题或异常情况,虽然不会导致系统崩溃或功能失效,但需要开发人员注意和处理,以避免可能的错误。

  4. ERROR(错误): 用于记录错误事件,表示程序发生了一些可恢复的错误,但并未导致程序完全失败,通常需要开发人员及时处理以保证系统的正常运行。

  5. FATAL(致命错误): 用于记录严重错误事件,表示程序发生了无法恢复的错误,导致程序崩溃或功能失效,需要立即进行修复和处理,以保证系统的稳定性和可靠性。

基于这个项目,目前我们实现的时文件版本;因此我们需要打印出日志等级、文件名称、报错行、时间戳。

日志功能代码

Log.hpp

#pragma once
#include <iostream>
#include <string>
#include "util.hpp"
using namespace std;
namespace ns_log
{using namespace ns_util;// 日志等级enum{INFO,    // 就是整数0DEBUG,   // 1WARNING, // 2ERROR,   // 3FATAL    // 4};// 参数// 日志等级// 文件名// 行数// 标准输出流返回给用户inline ostream &Log(const string &level, const string &file_name, const int line){// 添加日志等级string message = "[";message += level;message += "]";// 添加报错文件名称message += "[";message += file_name;message += "]";// 添加报错行message += "[";message += to_string(line);message += "]";// 日志时间戳message += "[";message += TimeUtil::GetTimeStamp();message += "]";// cout 本质内部是包含缓冲区的//cout << message; // 不要endl刷新// 此时message 就在缓冲区中return cout;}
// LOG(INFO)<<"message"<<endl;
// 开放日志
#define LOG(level) Log(#level, __FILE__, __LINE__)
}

最后我们宏定义这个函数调用,参数#level 用于将参数 level 转换成一个字符串,参数__FILE____LINE__ 是预定义的宏,在编译时由编译器自动替换为当前源文件的文件名和代码行号。

时间信息也是一个公用的信息我们会在另一个文件中实现。


编译功能开发

首先我们要明白这个模块只负责进行代码编译,那么意味着我们目前默认是能够接收远端提交的代码文件,并且这个文件对于我们编译模块来说是一个临时文件,如果编译成功后也会形成一个临时的可执行文件,因此在这个模块中我们还需要一个临时文件的文件夹。但是对于这个模块中目前的进程是用来接收代码文件的,对于提交的代码文件我们如何处理呢?

创建子进程和程序替换

因为编译对于操作系统来也是执行了一个程序,只不过这个程序很小,过程快而已;因此我们可以创建一个子进程,让子进程进行程序替换,替换我们的编译指令程序。

重定向

编译代码就两种结果:编译成功或者编译失败;编译成功就是我们想要的结果,可以通过判断是否生成可执行文件判断这个结果;对于编译失败,编译失败的信息会向我们的显示器打印,但是我们是要将信息返回给使用者的;因此我们就需要将错误信息重定向到一个错误文件中。

编译功能代码

compiler.hpp

// 主要进行编译服务
#pragma once// 编译服务器
#include <iostream>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#include"../comm/util.hpp"
#include"../comm/Log.hpp"
using namespace std;// 只负责进行代码编译// 默认代码能够接收// 远端提交代码// 一定要能够形成临时文件// 第一种编译通过
// 第二种编译出错
// 本质是像stderr错误中打印---->需要形成临时文件 ,帮助我们保存编译出错的结果的// 不能让这个进程编译
// 核心思路:创建子进程(fork())---->子进程完成编译代码 编译错误向stderr中打印(默认是向显示屏打印) 需要重定向到stderr中
// 父进程继续执行namespace ns_compiler
{//引入路径拼接功能using namespace ns_util;using namespace ns_log;class Compiler{public:Compiler(){}~Compiler(){}//编译//返回值:编译成功:true 编译失败:false//参数:编译代码的文件名//1234//./temp/1234.cpp//./tmep/1234.exe//./temp/1234.stderr//编译错误临时文件static bool Compile(const std::string &file_name)//temp文件夹保存临时文件{pid_t pid = fork();if(pid<0){//创建子进程失败LOG(ERROR)<<"内部错误,创建子进程失败"<<"\n";return false;}else if(pid==0){//需要一个错误文件int _stderr = open(PathUtil::Stderr(file_name).c_str(),O_CREAT|O_WRONLY,644);//if(_stderr<0){//打开文件失败LOG(WARNING)<<"没有成功形成stderr文件"<<"\n";exit(1);}//编译错误时才会向文件中写入//重定向dup2(_stderr,2);//子进程:调用编译器完成对代码的编译工作//程序替换//不需要冗余的路径//g++ -o target src -std=c++11//程序替换并不影响文件描述符表//我想执行谁,怎么执行execlp("g++","g++","-o",PathUtil::Exe(file_name).c_str(),PathUtil::Src(file_name).c_str(),"-std=c++11",nullptr/*不要忘记*/);LOG(ERROR) <<"启动编译器g++失败,可能是参数错误"<<"\n";exit(2);}else {//父进程waitpid(pid,nullptr,0);//编译是否成功---->是否形成可执行程序if(FileUtil::IsFileExists(PathUtil::Exe(file_name))){LOG(INFO)<<PathUtil::Src(file_name)<<" 编译成功!"<<"\n";return true;}}LOG(ERROR)<<"编译失败,没有形成可执行程序"<<"\n";return false;}};
}

until.hpp

#pragma once
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
using namespace std;
namespace ns_util
{const std::string temp_path = "./temp/";// 路径class PathUtil{public:static std::string AddSuffix(const std::string &file_name, const std::string suffix){std::string path_name = temp_path;path_name += file_name;path_name += suffix;return path_name;}// 构建源文件路径+后缀的完整文件名// 1234->./temp/1234.cppstatic std::string Src(const std::string &file_name){return AddSuffix(file_name, ".cpp");}// 构建可执行程序的完整路径+后缀static std::string Exe(const std::string &file_name){return AddSuffix(file_name, ".exe");}// 构建该程序对应的标准错误完整的的路径+后缀名static std::string Stderr(const std::string &file_name){return AddSuffix(file_name, ".stderr");}};class FileUtil{public:static bool IsFileExists(const std::string path_name){// 通过判断获取文件属性判断文件是否存在struct stat st;if (stat(path_name.c_str(), &st) == 0){// 获取文件属性成功代表文件存在return true;}return false;}};class TimeUtil{public:static string GetTimeStamp(){struct timeval _time;gettimeofday(&_time, nullptr);return to_string(_time.tv_sec);}};
}

今天对项目编译和日志功能开发的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 


http://www.ppmy.cn/ops/36515.html

相关文章

#9松桑前端后花园周刊-React19beta、TS5.5beta、Node22.1.0、const滥用、jsDelivr、douyin-vue

行业动态 Mozilla 提供 Firefox 的 ARM64 Linux二进制文件 此前一直由发行版开发者或其他第三方提供&#xff0c;目前Mozilla提供了nightly版本&#xff0c;正式版仍需要全面测试后再推出。 发布 React 19 Beta 此测试版用于为 React 19 做准备的库。React团队概述React 19…

《Video Mamba Suite》论文笔记(1)Mamba在时序建模中的作用

原文链接 https://arxiv.org/abs/2403.09626https://arxiv.org/abs/2403.09626 原文代码 https://github.com/OpenGVLab/video-mamba-suitehttps://github.com/OpenGVLab/video-mamba-suite 原文笔记 What 《Video Mamba Suite: State Space Model as a Versatile Altern…

并发与线程、进程基本概念

目录 并发 可执行程序 进程与线程 进程 线程 线程与进程局别 并发的实现 多进程并发 多线程并发 并发 并发字面上就是多个相对独立的事件一起发生。代表了在同一时间内处理多个任务或进程的能力。我们日常生活中有很多并发例子&#xff0c;如一边看电影一边吃零食&…

iOS使用webSocket通信

一、什么是webSocket webSocket是HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术&#xff0c;属于应用层协议。它基于TCP传输协议&#xff0c;并复用HTTP的握手通道。对大部分web开发者来说&#xff0c;上面这段描述有点枯燥&#xff0c;其实只要记住几点&#x…

蚂蚁笔记(非官方版)复活

蚂蚁笔记&#xff0c;官方已经停止维护了。但我觉得挺好用的&#xff0c;就重新拉分支&#xff0c;并进行了开发和维护。 开源仓库地址&#xff1a;GitHub - wiselike/leanote-of-unofficial: Leanote of non-official nolicensed version 同时&#xff0c;公开了docker一键部…

Linux详解:进程等待

文章目录 进程等待等待的必要性进程等待的方法waitwaitpid获取子进程status阻塞等待 与 非阻塞等待 进程等待 等待的必要性 子进程退出&#xff0c;父进程不进行回收的话&#xff0c;就可能造成僵尸进程&#xff0c;进而造成内存泄露 如果进程进入了僵尸状态&#xff0c;kill…

【Linux深度学习笔记5.7】

5.6学习笔记 文件查找: 语法:find $路径 name | type | perm | size | atime | mtime | ctime 操作对象find /opt/ -name a.txt ----> -iname (忽略大小写)find / -perm 000 ----> 权限查找find / -size 5M ----> 大小查找 5M (大于5M) -5M (小于5M)find /etc/…

javacv实时解析pcm音频流

javacv实时解析pcm音频流 解析代码 try (ByteArrayInputStream inputStream new ByteArrayInputStream(bytes);){FFmpegFrameGrabber grabber new FFmpegFrameGrabber(inputStream);// PCM S16LE 格式grabber.setFormat("s16le");// 采样率grabber.setSampleRate(1…