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

目录

日志功能开发

常见的日志等级

日志功能代码

编译功能开发

创建子进程和程序替换

重定向

编译功能代码


日志功能开发

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

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

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

常见的日志等级

  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,    // 就是整数0
        DEBUG,   // 1
        WARNING, // 2
        ERROR,   // 3
        FATAL    // 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.cpp
        static 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.mfbz.cn/a/600251.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

国货美妆进入新纪元之际,毛戈平打好“高端牌”了吗?

当前&#xff0c;国内美妆市场的格局已发生较大变化。 一边是国际品牌的“退场”&#xff0c;据统计&#xff0c;2023年退出中国市场的海外美妆品牌有20多个&#xff1b;一边是国内美妆品牌正在迎来自己的时代。 根据魔镜洞察数据&#xff0c;2024年一季度&#xff0c;国货彩…

论文辅助笔记:Tempo之modules/lora.py

1 LoRALayer 基类 2 Linear 2.1 __init__ 2.2 reset_parameter & train 2.3 forward 3 MergeLinear 3.1__init__ enable_lora指定了哪些输出特征使用lora 3.2 reset_parameters & zero_pad & merge_AB 3.3 train & forward

纯血鸿蒙APP实战开发——底部面板嵌套列表滑动案例

介绍 本示例主要介绍了利用panel实现底部面板内嵌套列表&#xff0c;分阶段滑动效果场景。 效果图预览 使用说明 点击底部“展开”&#xff0c;弹出panel面板。在panel半展开时&#xff0c;手指向上滑动panel高度充满页面&#xff0c;手指向下滑动panel隐藏。在panel完全展开…

从零开始的软件测试学习之旅(七)接口测试三要素及案例

接口测试三要素及案例 接口测试介绍接口预定义接口测试的主要作用测试接口流程如下接口测试三要素接口测试分类RESTful架构风格RESTful架构三要素要素一要素二要素三 RESTful架构风格实现案例复习复盘 接口测试介绍 接口介绍 不同主体之间进行通信的通道,它应具有一套规范/标准…

Vulnhub项目:NAPPING: 1.0.1

1、靶机介绍 靶机地址&#xff1a;Napping: 1.0.1 ~ VulnHub 2、渗透过程 老规矩&#xff0c;先探测&#xff0c;靶机ip&#xff1a;192.168.56.152 本机ip&#xff1a;192.168.56.146 来看一看靶机开放哪些端口&#xff0c;nmap一下 nmap -sS -sV -A -T5 192.168.56.152 开…

UE5自动生成地形二:自动生成插件

UE5自动生成地形二&#xff1a;自动生成插件 Polycam使用步骤 本篇主要讲解UE5的一些自动生成地形的插件 Polycam 此插件是通过现实的多角度照片自动建模生成地形数据&#xff0c;也是免费的。这里感谢B站up主古道兮峰的分享 Polycam网站 插件下载地址 插件网盘下载 提取码&a…

6.移除元素

文章目录 题目简介题目解答解法一&#xff1a;双指针代码&#xff1a;复杂度分析&#xff1a; 解法二&#xff1a;双指针优化代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 相关的讲解&#xff01;&#x1f600; 题目简…

Portforge:一款功能强大的轻量级端口混淆工具

关于Portforge Portforge是一款功能强大的轻量级端口混淆工具&#xff0c;该工具使用Crystal语言开发&#xff0c;可以帮助广大研究人员防止网络映射&#xff0c;这样一来&#xff0c;他人就无法查看到你设备正在运行&#xff08;或没有运行&#xff09;的服务和程序了。简而言…

数据库(MySQL)—— 初识和创建用户

数据库&#xff08;MySQL&#xff09;—— 初识 什么是数据库数据库的种类创建用户mysql -h 主机名或IP地址 -u 用户名 -p 登录mysqlSELECT USER(); 查看当前用户切换用户GRANT ALL PRIVILEGES ON 赋予用户权限 REVOKE 撤销权限示例注意事项 MySQL的图形化界面工具查看所有用户…

ldap对接jenkins

ldap结构 配置 - jenkins进入到 系统管理–>全局安全配置 - 安全域 选择ldap - 配置ldap服务器地址&#xff0c;和配置ldap顶层唯一标识名 配置用户搜索路径 - 配置管理员DN和密码 测试认证是否OK

【xxl-job | 第三篇】SpringBoot整合xxl-job

文章目录 3.SpringBoot整合xxl-job3.1定时任务服务配置3.1.1导入maven依赖3.1.2yml配置3.1.3XxlJobConfig配置类3.1.4定时任务类 3.2xxl-job配置3.2.1新增执行器3.2.2新增任务3.2.3执行任务3.2.4查看日志3.2.5查看任务后台日志 3.3小结 3.SpringBoot整合xxl-job 3.1定时任务服…

B端UX/UI设计面试作品集分层源文件figmasketch模板

当您考虑找工作时&#xff0c;是否曾质疑过项目复盘作品集的重要性&#xff1f;实际上&#xff0c;一份精心准备的项目复盘作品集对于求职者来说具有无可估量的价值&#xff0c;特别是对于设计师这一职业领域。 以下所述或许对您而言已非陌生。您的作品集应当成为您专业技能与…

嵌入式linux学习第三天汇编语言点灯

嵌入式linux学习第三天汇编语言点灯 今天学习如何在linux板子上点灯。 I.MX6U GPIO 详解 我们发现I.MX6U GPIO是分为两类的&#xff0c;&#xff1a;SNVS 域的和通用的。在讨论i.MX6U或类似的复杂微处理器时&#xff0c;了解其GPIO&#xff08;通用输入输出&#xff09;引脚…

vivado Zynq UltraScale+ MPSoC 比特流设置

Zynq UltraScale MPSoC 比特流设置 下表所示 Zynq UltraScale MPSoC 器件的器件配置设置可搭配 set_property <Setting> <Value> [current_design] Vivado 工具 Tcl 命令一起使用。

科研学习|可视化——ggplot2版本的网络可视化

ggplot2是R语言中一个非常流行的数据可视化包&#xff0c;它也可以用于网络可视化。以下是三个基于ggplot2并专门用于网络可视化的R包&#xff1a; ggnet2: 这个包的使用方法与传统的plot函数相似&#xff0c;易于使用。更多信息可在其官方页面查看&#xff1a;ggnet2 geomnet…

python+flask+ldap3搭建简易版IDaaS系统(前端站点)

Python工具开源专栏 Py0006 pythonflaskldap3搭建简易版IDaaS系统&#xff08;前端站点&#xff09; Python工具开源专栏前言目录结构前端网站的部分演示首页查询数据数据同步数据关联查询系统日志 完整代码已在GitHub上开源 前言 pythonflaskldap3搭建简易版IDaaS系统的前端站…

VALSE 2024 Tutorial内容总结--开放词汇视觉感知

视觉与学习青年学者研讨会&#xff08;VALSE&#xff09;旨在为从事计算机视觉、图像处理、模式识别与机器学习研究的中国青年学者提供一个广泛而深入的学术交流平台。该平台旨在促进国内青年学者的思想交流和学术合作&#xff0c;以期在相关领域做出显著的学术贡献&#xff0c…

【Linux进程信号(一)】信号概念/产生/保存/处理

目录 入门 前&后台进程 前台进程&#xff1a; 后台进程 常用命令 ./XXX & fg命令 & bg命令 Ctrl c / Ctrl \ 信号的概念 信号的产生 1.键盘产生 2.系统调用指令 3.异常 4.软件条件 信号的保存 信号的处理 1.信号屏蔽字 2.未决信号表 3.信号处理…

layui 数据表格 自动定位新增行位置

由于数据表格新增行后没有到新增到当前位置 继续增加的需求&#xff1a; 因为自己是新增行后到最后一行的 所以 就定位到最后一行 并且 高亮 高亮颜色浅 可自行更改 整理了一下 可根据 情况 修改 // 初始化滚动条位置变量 let tableScroll {scrollTob: 0,scrollLeft: 0,…

【busybox记录】【shell指令】comm

目录 内容来源&#xff1a; 【GUN】【comm】指令介绍 【busybox】【comm】指令介绍 【linux】【comm】指令介绍 使用示例&#xff1a; 逐行比较两个排序后的文件 - 默认输出 逐行比较两个排序后的文件 - 如果一个文件的排序有问题&#xff0c;那么反错&#xff08;默认&…
最新文章