【Linux】日志与守护进程

news2024/12/23 14:14:27

目录

一、预备知识

二、打印日志

三、守护进程

1、前置知识

2、守护进程


一、预备知识

日志是有等级的,表明该条日志的重要程度,一般分为以下几个级别:

#define DEBUG 0 //调试信息
#define INFO  1 //正常运行
#define WARNING 2 //报警
#define ERROR 3 //正常错误
#define FATAL 4 //严重错误

在打印日志时,通常需要用到可变参数列表。对于可变参数列表的读取,可以使用以下几个宏:

  • va_list
  • va_arg
  • va_start
  • va_end;
void logMessage(int level, char* format, ...)
{
    va_list p;           //char* 类型指针
    va_start(p, format); //把指针p指向可变参数部分的起始地址
    int a = va_arg(p. int); //根据指定的类型提取参数   
    va_end(p);            //p = NULL
}

二、打印日志

 在打印日志时,一般都会有固定的格式,把日志格式放到一个缓冲区里,日志内容放到另一个缓冲区里。

 例如:现在我们想打印日志的格式是 日志等级 时间 进程pid 消息体。那么就可以把 日志等级 时间 进程pid 放到 logleft 缓冲区中,消息体放到 logright 缓冲区中。

把可变参数列表元素打印到文件的函数:

int vsnprintf(char *str, size_t size, const char *format, va_list ap);

 获取当前时间函数:

time_t time(time_t *tloc);

 将时间转换成对应结构体的函数:

struct tm *localtime(const time_t *timep);

 完整代码:

#pragma once

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <ctime>
using namespace std;

// 日志是有日志等级的
enum
{
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR,
    FATAL,
    UKNOWN
};

string filename = "logfile";

static string toLevelString(int level)
{
    switch (level)
    {
        case DEBUG: return "DEBUG";
        case INFO: return "INFO";
        case WARNING: return "WARNING";
        case ERROR: return "ERROR";
        case FATAL: return "FATAL";
        default: return "UKNOWN";
    }
}

string getTime()
{
    time_t curr = time(nullptr);
    struct tm* tmp = localtime(&curr);

    char buffer[128];
    snprintf(buffer, sizeof(buffer), "[%d-%d-%d %d:%d:%d]", tmp->tm_year + 1900, tmp->tm_mon, tmp->tm_mday,
                                                          tmp->tm_hour, tmp->tm_min, tmp->tm_sec);

    return buffer;
}

//日志格式:左半部分:日志等级 时间 pid 
//         右半部分:消息体
void logMessage(int level, const char* format, ...)
{
    char logLeft[1024];
    string level_string = toLevelString(level);
    string curr_time = getTime();
    snprintf(logLeft, sizeof(logLeft), "[%s %s %d]", level_string.c_str(), curr_time.c_str(), getpid());

    char logRight[1024];
    va_list p;
    va_start(p, format);
    vsnprintf(logRight, sizeof(logRight), format, p);
    va_end(p);

    //打印日志
    //printf("%s %s\n", logLeft, logRight);

    //保存到文件中
    FILE* fp = fopen(filename.c_str(), "a");
    if(fp == nullptr) return;

    fprintf(fp, "%s%s\n", logLeft, logRight);
    fflush(fp);

    fclose(fp);
}

三、守护进程

1、前置知识

首先后台创建几个进程:

 查看刚刚创建的进程:

 进程的属性中除了我们熟知的PPID与PID外, PGID 是进程组。 SID 是会话编号。 TTY 是终端文件。

 进程组的组长,都是多个进程中的第一个,进程组的编号就是第一个进程的PID。

 当我们从本地或远端登录Linux时,Linux会给用户分配一个命令行解释器,即bash进程。basn进程自己成立进程组,自己成立一个会话,会话编号就是bash进程的PID。未来所起的所有进程与进程组都属于这个会话。

 一个进程组被创建出来,是为了完成一个任务,查看后台任务的指令:

jobs

 每一组进程都有一个编号,称为任务编号。

把后台任务提到前台的指令:

fg [任务编号]

 

 把前台任务放到后台的指令:

ctrl + z
bg [任务编号]

 创建进程组是为了完成任务的。在用户的视角,可以把一个进程组叫做一个任务。进程组可能包含一个或多个进程。

 任务分为前台任务与后台任务。如果把后台任务提到前台,老的前台任务就无法运行了。在一个会话中,任何时刻,都只能有一个前台任务在运行。这就是为什么我们在命令行启动一个进程时,bash就无法运行了的原因。

 用户登录就是创建一个会话并启动bash任务,在命令行中启动进程,就是创建新的前后台任务。用户退出就是销毁会话,可能会影响会话内部的所有任务。

 网络服务器为了不受到用户的登录与注销的影响,一般就会通过守护进程的方式运行。

2、守护进程

守护进程是把一个任务独立出来,自己成为一个会话,以免受到其他会话的影响。

创建守护进程的函数:

pid_t setsid(void);

 谁调用这个函数,谁就把自己设置为守护进程。函数调用成功,返回调用这个函数的进程的pid。失败则返回-1,错误码被设置。

需要注意的是,一个进程组的组长,不能调用 setsid 函数

再创建守护进程时,有时会需要更改守护进程的工作路径,更改函数:

int chdir(const char *path);

 当一个进程编程守护进程时,他就不应该与标准输出、标准输入、标准错误文件有交互了。我们可以接用文件黑洞 /dev/null 来处理。 /dev/null 在任何一个Linux系统里都一定存在,向这个文件中写入的所有数据都会消失,读取这个文件直接返回。

守护进程完整代码:

#pragma once

#include <unistd.h>
#include <cstdlib>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log.hpp"
#include "error.hpp"

//守护进程是孤儿进程的一种
void Daemon()
{
    //1.忽略一些异常信号
    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);

    //2.让自己不要成为组长
    if(fork() > 0) exit(0); //让父进程直接退出,这样保证子进程一定不是组长,一定可以调用setsid
                            //因为进程组的编号是父进程的pid

    //3.新建会话,自己成为会话的话首进程
    pid_t ret = setsid();
    if((int)ret == -1)
    {
        logMessage(FATAL, "deamon error, code: %d, string: %s", errno, strerror(errno));
        exit(SETSID_ERR);
    }

    //4.可以更换守护进程的工作目录
    //chdir

    //5.处理后续的对于文件描述符0, 1, 2的问题
    int fd = open("/dev/null", O_RDWR);
    if(fd < 0)
    {
        logMessage(FATAL, "open error, code: %d, string: "%s", error, strerror(errno));
        exit(OPEN_ERR);
    }

    dup2(fd, 0);
    dup2(fd, 1);
    dup2(fd, 2);
    close(fd);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/772618.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python爬虫+可视化案例】采集电商网站商品数据信息,并可视化分析

爬虫可视化案例 &#xff1a;苏宁易购 案例所需要掌握的知识点&#xff1a; selenium的使用html标签数据解析方法 需要准备的环境&#xff1a; python 3.8pycharm 2022专业版selenium python里面的第三方库 可以用来操作浏览器 爬虫代码展示 所需模块 【代码领取 请看文末…

017 - STM32学习笔记 - SPI读写FLASH(二)-flash数据写入与读取

016 - STM32学习笔记 - SPI访问Flash&#xff08;二&#xff09; 上节内容学习了通过SPI读取FLASH的JEDEC_ID&#xff0c;在flash资料的指令表中&#xff0c;还看到有很多指令可以使用&#xff0c;这节继续学习使用其他指令&#xff0c;程序模板采用上节的模板。 为了方便起…

为何异地销号这么难?这些注意事项要熟记!

最近有不少小伙伴私信小编&#xff0c;他们在网上办理的大流量手机号卡&#xff0c;用了一段时间之后想换其他的卡&#xff0c;所以想注销当前用的卡&#xff0c;但是注销的时候确实屡屡碰壁&#xff0c;程序还比较繁琐&#xff0c;有的甚至申请注销了几个月还注销不掉&#xf…

在Microsoft Excel中如何合并多个表格

如果你问那些处理数据的人,你会知道合并 Excel 文件或合并工作簿是他们日常工作的一部分。 Power Query 是将多个 Excel 文件中的数据合并或组合到一个文件中的最佳方式。你需要将所有文件存储在一个文件夹中,然后使用该文件夹将这些文件中的数据加载到高级查询编辑器中。它…

了解kubernetes部署:namespace和Node设置

节点及namespace的设置 kubectlcreate-f/opt/kubernetes/namespaces.yaml 通过此命令我们创建了如下namespace: ns-elasticsearch:elasticsearch相关  ns-rabbitmq:rabbitmq相关  ns-javashop&#xff1a;javashop应用相关 接下来我们要根据具体情况安排各个节点的部署规划…

CSS科技感四角边框

实现效果:使用before和after就可以实现,代码量不多,长度颜色都可以自己调整 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title><style>*{margin:0;padding:0;}html,body{…

OBS录制双屏

1.设置视频分辨率&#xff0c;假如要录制两个1920x1080分辨率的屏幕&#xff0c;那就把需要录制的分辨率改为3840x10802. 添加显示器采集 3.点击开始录制 4.最终效果

python_PyQt5开发股票指定区间K线操作工具_裸K

目录 写在前面&#xff1a; 工具使用演示&#xff1a; 代码&#xff1a; 导入包 横坐标控件、K线控件、带查询下拉列表控件 K线图控件 主界面代码 执行代码 写在前面&#xff1a; 继前面文章提到筛出低位股票后&#xff0c;想逐一查看这些股票今年的K线走势&#xff…

香港视频直播服务器需要多大的带宽(带宽计算方式)

​  香港视频直播服务器需要多大的带宽(怎么计算带宽大小)。目前短视频行业兴起&#xff0c;有许多人也想利用香港服务器搭建一个直播平台&#xff0c;但无奈不知道怎么选择资源大小&#xff0c;或者说什么样的配置能够满足直播的需求。关于直播的带宽大小和流量消耗的计算同…

记录一次抓取WiFi驱动日志以及sniffer日志

起因 路由器桥接一个WiFi&#xff0c;然后设备连接这个路由器的WiFi&#xff0c;发现网络不可用&#xff0c;而手机或者电脑连接就没问题&#xff0c;与供应商沟通问题&#xff0c;需要抓取日志&#xff0c;记录一下 抓取WLAN DRIVER WLAN FW3日志 进入开发者模式打开启动WL…

hive常用方法

日期类 Date_sub 日期进行加减 &#xff0c;正的减&#xff0c;负的加 select current_date -- 当前日期,date_sub(current_date,1) -- 前一日,date_sub(current_date,-1) -- 后一日 from edw.test;字符类 split 该函数是分割字符串 &#xff0c;按照…

2023 年中国大学生计算机设计大赛上海决赛区正式开启!

中国大学生计算机设计大赛&#xff08;下文简称“大赛”&#xff09;是由教育部认证、我国高校面向本科生最早的赛事之一&#xff0c;自 2008 年开赛起&#xff0c;至今已是第十六届。大赛属于全国普通高校大学生竞赛排行榜榜单赛事&#xff0c;由教育部高校与计算机相关的教指…

结构型模式 - 组合模式

概述 对于这个图片肯定会非常熟悉&#xff0c;上图我们可以看做是一个文件系统&#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树&#xff0c;当我们找到某个叶子节点后&#xff0c;就可以对叶子节点进行相关的操作。可以将这颗树理…

MySql 优化实例:修改 cross join 方式为子查询方式,以求改变执行计划

MySql 优化实例:修改 cross join 方式为子查询方式,以求改变执行计划 问题来源问题的追溯尝试使用索引排除日志表,验证查询速度变形查询指令修改程序中的调用指令对原有查询条件进行位置调整事后总结in 的使用初学者建议执行计划问题来源 问题内容出自问答:https://ask.cs…

【Hydro】HBV-light模型介绍及下载

HBV-light模型 HBV模型是一种模拟流域径流的半分布式水文模型。 什么是HBV-light&#xff1f; HBV模型软件除了原版&#xff08;版本由S. Bergstrm1976年开发&#xff09;之外还有很多不同版本。HBV-light在其先前版本中已在乌普萨拉大学开发&#xff08;并在俄勒冈州州立大…

业务开发“银弹” ——低代码开发平台

一、现状 低代码开发平台要让每个人&#xff0c;包括开发者和普通业务人员&#xff0c;都能够成为企业数字化过程中的主导者和构建者&#xff01;让普通人更容易上手&#xff01; 基于这一目标&#xff0c;应用需求多的云服务商成为低代码投资的主要来源。一家云服务商如谷歌云…

性能测试需求分析怎么做?(中)

本系列文章我们为大家系统地介绍一下性能测试需求分析&#xff0c;让大家全面掌握性能测试的第一个环节。本系列文章将会从性能测试需求分析整体概述、性能测试需求分析内容、性能测试需求分析方法这三个方面进行展开。在&#xff08;上&#xff09;部分中&#xff0c;我们为大…

linux之Ubuntu系列(六)用户管理 终端命令 which 查看执行命令所在的位置

提示 /etc/passwd 是用于保存用户信息的文件 可以用cat 命令查看 cat /etc/passwd/usr/bin/passwd 是用于修改用户密码的 程序 &#xff0c;是程序 程序 &#xff0c; which 命令 可以查看执行命令所在的位置 # 输出 /bin/ls which ls # 输出 /usr/sbin/useradd which useradd…

安达发|某大厂使用APS计划排程真实成功案例

在很多群里、朋友圈、公众号上可以看到&#xff0c;很多精益咨询老师认为&#xff0c;不仅ERP不啥用&#xff0c;APS更是无聊之举&#xff0c;而且肯定是用不好的。但&#xff0c;事实上可能还真不是这样的。 一个深圳的客户&#xff0c;用了APS以后&#xff0c;不仅装配的齐套…

【AI绘画】AI绘画乐趣:稳定增强扩散技术展现

目录 前言一、Stable Diffusion是什么&#xff1f;二、安装stable-diffusion-webui1. python安装2. 下载模型3. 开始安装&#xff1a;4. 汉化&#xff1a;5. 模型使用&#xff1a;6. 下载新模型&#xff1a;7. 基础玩法 三、总结 前言 本文将借助stable-diffusion-webui项目来…