IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Qt Apache日志分析 -> 正文阅读

[系统运维]Qt Apache日志分析

Qt Apache日志分析,httpLogsView是Apache日志分析的一款专业工具,但很多统计功能收费,且IP归属是英文显示。Qt Apache日志分析仿照httpLogsView实现一款具有类似功能的工具软件,方便站点管理。

Download - http Logs Viewer
https://www.apacheviewer.com/download/

Apache日志可文本查看,分为7个部分:

(1)第一项信息是远程主机的地址,即它表明访问网站的究竟是谁。(可以要求apache查出所有的主机名字,并在日志文件中用主机名字来替代IP地址,但这种做法会极大的影响服务器记录日志的速度,从而降低整个网站的效率,不值得推荐)。

然而,如果确实有必要让apache找出远程主机的名字,可以使用如下指令:

HostNameLookups on

如果HostNameLookups设置成double而不是on,日志记录程序将对它找到的主机名字进行反向查找,验证该主机名字确实指向了原来出现的IP地址。

(2)日志记录的第二项是空白,用一个“-”占位符替代。实际上绝大多数时候这一项都是如此。这个位置用于记录浏览者的标识,这不只是浏览者的登录名字,而是浏览者的email地址或者其他唯一标识符。这个信息由identd返回,或者直接由浏览器返回。(为了避免用户的邮箱被垃圾邮件骚扰,第二项就用“-”取代了)。

(3)日记记录的第三项也是空白。这个位置用于记录浏览者进行身份验证时提供的名字。当然,如果网站的某些内容要求用户进行身份验证,那么这项信息室不会空白的。但是,对于大多数网站来说,日志文件的大多数记录中这一项仍旧是空白的。

(4)日志记录的第四项是请求的时间。这个信息用方括号包围,而且采用“公用日志格式”或者“标准英文格式”。因此,时间信息最后的“-0400”表示服务器所处时区位于UTC之前的4小时。

(5)日志记录的第五项信息或许是整个日志记录中最有用的信息,它告诉我们服务器受到的是一个什么样的请求。该项信息的典型格式是“METHOD RESOURCE PROTOCOL”即“方法 资源 协议”(我们通常进行日志监控的时候,主要也是看这项内容)。例子中METHOD是GET,还有POST、HEAD等其他类型,主要是这三种。

RESOURCE是指浏览者向服务器请求的文档或者URL。在这个例子中,浏览者请求的是“/”,即网站的根或者主页。大多数情况下,“/”指向DocumentRoot目录的index.html文档,但根据服务器配置的不同也可能指向其他文件。

PROTOCOL通常是HTTP,然后再加上版本号。

(6)日志的第六项信息是状态代码。它告诉我们请求是否成功,或者遇到了什么样的错误。大多数时候这项是200,它表示服务器已经成功的响应浏览器的请求,一切正常。(以2开头的状态码表示成功,以3开头的状态码表示由于各种不同的原因用户请求被重定向到了其他位置,以4开头的状态代码表示客户端存在某种错误,以5开头的状态代码表示服务器遇到了某个错误)。

(7)日志记录的第七项表示发送客户端的总字节数。它告诉我们传输是否被打断(即该数值是否和文件的大小相同)。

GitHub - lionsoul2014/ip2region: Ip2region is a offline IP location library with accuracy rate of 99.9% and 0.0x millseconds searching performance. DB file is ONLY a few megabytes with all IP address stored. binding for Java,PHP,C,Python,Nodejs,Golang,C#,lua. Binary,B-tree,Memory searching algorithm
https://github.com/lionsoul2014/ip2region

IP归属地使用ip2region,计划使用https://www.ip138.com/iplookup.asp?ip=19.168.10.10&action=2,但有访问控制和反爬虫,轻量可以使用。

?开始使用这个接口https://www.ip138.com/iplookup.asp?ip=19.168.10.10&action=2获取IP归属地,https出现以下错误

?QT连接HTTPS,解决HTTPS问题_拽拽就是我的博客-CSDN博客_qt支持https

https://blog.csdn.net/qq_32355021/article/details/124089942

Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions

http://slproweb.com/products/Win32OpenSSL.html

这个链接没有1.0的,从下面的old链接下载源码然后编译

编译最后报cl.exe错误,改调用Python抓取IP归属地。?

?创建IP归属地线程

    mIP138 = new IP138(this);
    connect(mIP138, SIGNAL(sendData(QString,QString)), this, SLOT(updateData(QString,QString)));
    connect(mIP138, SIGNAL(done()), this, SLOT(getIP138Done()));
    connect(mIP138, SIGNAL(done()), mIP138, SLOT(quit()));

timer随线程更新界面归属地

    mUpdateTimer = new QTimer(this);
    mUpdateTimer->setInterval(20);
    connect(mUpdateTimer, SIGNAL(timeout()), this, SLOT(timerout()));

?程序启动时数据库获取所有归属地数据,减少界面更新和线程操作,目前五万条数据

void MainWindow::selectAllIP138()
{
    if (!mAllIP138Map.isEmpty())
    {
        return;
    }

    mAllIP138Map.clear();

    QString retStr = mDBHelper.getConnectDB();
    if (!retStr.isEmpty())
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("数据库连接失败:\n%1").arg(retStr), true);
        return;
    }

    QStringList columnLst;
    columnLst << "ip_address" << "ip_138";

    QString str = QStringLiteral("select columns from t_ip_138;");

    QList<QStringList> retLst = mDBHelper.getSqlSelect(str, columnLst);
    foreach (QStringList ret, retLst)
    {
        mAllIP138Map.insert(ret[0], ret[1].replace(" 0", ""));
    }
}

数据导入和分析,如果有数据库查不到归属地的IP,转到线程获取

void MainWindow::on_pushButton_data_import_clicked()
{
    QString dataImportFile = QFileDialog::getOpenFileName(this, QStringLiteral("数据导入"), QStringLiteral("."), QStringLiteral(""));
    if (!dataImportFile.isEmpty())
    {
        QFile file(dataImportFile);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            return;
        }

        if (mIP138->isRunning())
        {
            mIP138->quit();
            mIP138->wait();
        }

        if (mUpdateTimer->isActive())
        {
            mUpdateTimer->stop();
        }

        QList<LogData> dataLst;
        mIPLst.clear();
        mDataQueue.clear();
        mTableIndexMap.clear();
        mIsDone = false;

        QTextStream in(&file);
        in.setCodec("UTF-8");

        while (!in.atEnd())
        {
            QString str = in.readLine();
            if (!str.isEmpty())
            {
                QStringList strLst = str.split(" ");
                QString ip = strLst[0];
                QString dateTime = strLst[3].replace("[", "");
                QString statusCode = strLst.at(strLst.size() - 2);
                QString size = strLst.at(strLst.size() - 1);
                QString url = str.split("\"")[1];

                {
                    QStringList tmpLst = dateTime.split(":");
                    QString time = QStringLiteral("%1:%2:%3").arg(tmpLst[1]).arg(tmpLst[2]).arg(tmpLst[3]);

                    QStringList tmpLst2 = tmpLst[0].split("/");
                    QString date = QStringLiteral("%1/%2/%3").arg(tmpLst2[2]).arg(shortMonthToNumber(tmpLst2[1])).arg(tmpLst2[0]);

                    dateTime = QStringLiteral("%1 %2").arg(date).arg(time);
                }

                LogData data;
                data.IP = ip;
                data.DateTime = dateTime;
                data.StatusCode = statusCode;
                data.Size = size;
                data.URL = url;
                data.IP138 = mAllIP138Map.value(ip);

                dataLst.append(data);

                if (!mAllIP138Map.contains(ip) && !mIPLst.contains(ip))
                {
                    mIPLst.append(ip);
                }
            }
        }

        file.close();

        dataTableWidget(ui->tableWidget, dataLst);

        if (mIPLst.isEmpty())
        {
            informationMessageBox(QStringLiteral("提示"), QStringLiteral("分析完成"), true);
        }
        else
        {
            mIP138->setIPLst(mIPLst);
            mIP138->start();
        }
    }
}

?界面显示,为了timer更新界面速度快,提前把IP的row存起来,根据状态码设置行的不同颜色

void MainWindow::dataTableWidget(QTableWidget *tableWidget, QList<LogData> dataLst)
{
    int rowCount = tableWidget->rowCount();
    for (int i = rowCount; i > 0; --i)
    {
        tableWidget->removeRow(0);
    }

    QList<int> indexLst;
    foreach (LogData data, dataLst)
    {
        int rowCount = tableWidget->rowCount();
        tableWidget->insertRow(rowCount);

        QString ip = data.IP;
        QString country = data.IP138;
        QTableWidgetItem *itemIp = new QTableWidgetItem(ip);
        QTableWidgetItem *itemCountry = new QTableWidgetItem(country);
        QTableWidgetItem *itemDate = new QTableWidgetItem(data.DateTime);
        QTableWidgetItem *itemStatus = new QTableWidgetItem(data.StatusCode);
        QTableWidgetItem *itemSize = new QTableWidgetItem(data.Size);
        QTableWidgetItem *itemUrl = new QTableWidgetItem(data.URL);
        itemCountry->setToolTip(country);
        itemUrl->setToolTip(data.URL);

        if (country.isEmpty())
        {
            if (mTableIndexMap.contains(ip))
            {
                indexLst = mTableIndexMap.value(ip);
            }
            else
            {
                indexLst.clear();
            }

            indexLst.append(rowCount);
            mTableIndexMap.insert(ip, indexLst);
        }

        tableWidget->setItem(rowCount, 0, itemIp);
        tableWidget->setItem(rowCount, 1, itemCountry);
        tableWidget->setItem(rowCount, 2, itemDate);
        tableWidget->setItem(rowCount, 3, itemStatus);
        tableWidget->setItem(rowCount, 4, itemSize);
        tableWidget->setItem(rowCount, 5, itemUrl);

        for (int i = 0; i < tableWidget->columnCount(); ++i)
        {
            QString status = data.StatusCode;
            if (status.startsWith("2"))
            {
                tableWidget->item(rowCount, i)->setTextColor(QColor("blue"));
            }
            else if (status.startsWith("3"))
            {
                tableWidget->item(rowCount, i)->setTextColor(QColor("green"));
            }
            else if (status.startsWith("4"))
            {
                tableWidget->item(rowCount, i)->setTextColor(QColor("red"));
            }
            else if (status.startsWith("5"))
            {
                tableWidget->item(rowCount, i)->setTextColor(QColor("yellow"));
            }
        }
    }
}

?线程接收槽,归属地数据使用队列管理,每20条批量insert数据库

void MainWindow::updateData(QString ip, QString ip138)
{
    QString str = QStringLiteral("%1-%2").arg(ip).arg(ip138);
    mDataQueue.enqueue(str);

    mSQLLst.append(str);
    if (mSQLLst.size() >= 20)
    {
        get20SQL();
    }

    if (!mUpdateTimer->isActive())
    {
        mUpdateTimer->start();
    }
}

void MainWindow::get20SQL()
{
    QStringList tmpLst;
    for (int i = 0; i < 20; ++i)
    {
        tmpLst.append(mSQLLst.at(i));
    }

    for (int i = 0; i < 20; ++i)
    {
        mSQLLst.removeFirst();
    }

    insertSQL(tmpLst);
}

void MainWindow::insertSQL(QStringList sqlLst)
{
    QString retStr = mDBHelper.getConnectDB();
    if (retStr.isEmpty())
    {
        QString sqlValue;
        foreach (QString sql, sqlLst)
        {
            sqlValue += QStringLiteral("('%1', '%2'), ").arg(sql.split("-")[0]).arg(sql.split("-")[1]);
        }
        sqlValue.remove(sqlValue.lastIndexOf(", "), 2);

        QString str = mDBHelper.getSqlExcute(QStringLiteral("insert ignore into `t_ip_138` values%1;").arg(sqlValue));
        if (!str.isEmpty())
        {
            informationMessageBox(QStringLiteral("提示"), QStringLiteral("数据库Insert失败:\n%1").arg(str), true);
        }
    }
}

?timer更新界面归属地

void MainWindow::timerout()
{
    if (!mDataQueue.isEmpty())
    {
        QString str = mDataQueue.dequeue();
        QString ip = str.split("-")[0];
        QString ip138 = str.split("-")[1];

        QList<int> indexLst = mTableIndexMap.value(ip);
        foreach (int index, indexLst)
        {
            QTableWidgetItem *item = new QTableWidgetItem(ip138);
            ui->tableWidget->setItem(index, 1, item);
            ui->tableWidget->item(index, 1)->setTextColor(ui->tableWidget->item(index, 0)->textColor());
            ui->tableWidget->item(index, 1)->setToolTip(ip138);
        }

        ui->tableWidget->update();
        ui->tableWidget->viewport()->update();
        qApp->processEvents();
    }

    if (mIsDone && mDataQueue.isEmpty())
    {
        insertSQL(mSQLLst);
        mSQLLst.clear();

        mUpdateTimer->stop();
        ui->tableWidget->update();
        ui->tableWidget->viewport()->update();
        qApp->processEvents();

        informationMessageBox(QStringLiteral("提示"), QStringLiteral("分析完成"), true);
    }
}

线程run函数 ,两种接口,一种ip138网站,一种ip2region

void IP138::run()
{
    if (initPython())
    {
        mIsInit = true;
    }

    QString ret;
    bool flag = (mChoose == 0);
    foreach (QString ip, mIPLst)
    {
        if (flag)
        {
            ret = getIP2Region(ip);
            ret = QStringLiteral("%1 %2 %3 %4").arg(ret.split("|")[0]).arg(ret.split("|")[2]).arg(ret.split("|")[3]).arg(ret.split("|")[4]);
            ret.replace(" 0", "");
        }
        else
        {
            ret = getIP138(ip);
        }

        if (!ret.isEmpty())
        {
            emit sendData(ip, ret);
        }

        if (!flag)
        {
            this->msleep(mMsec + 1000);
        }
    }

    emit done();
}

QString IP138::getIP138(QString ip)
{
    if (!mIsInit)
    {
        return "";
    }

    PyObject *pFun = PyObject_GetAttrString(mPythonModule, "get_ip_138");
    PyObject *args = Py_BuildValue("(s)", ip.toStdString().c_str());
    PyObject *pRet = PyObject_CallObject(pFun, args);

    if (pRet == nullptr)
    {
        return "";
    }

    return getPythonListByIndex(pRet, 0).trimmed().replace("  ", " ");
}

QString IP138::getIP2Region(QString ip)
{
    if (!mIsInit)
    {
        return "";
    }

    PyObject *pFun = PyObject_GetAttrString(mPythonModule, "get_ip_region");
    PyObject *args = Py_BuildValue("(s)", ip.toStdString().c_str());
    PyObject *pRet = PyObject_CallObject(pFun, args);

    if (pRet == nullptr)
    {
        return "";
    }

    return getPythonListByIndex(pRet, 0).trimmed().replace("  ", " ");
}

Python归属地获取

# coding: utf-8

from urllib import request 
import re

import ssl 
ssl._create_default_https_context = ssl._create_unverified_context

import socket
socket.setdefaulttimeout(20.0)

from ip2Region import Ip2Region

def get_ip_138(ip):
    index_url = "https://www.ip138.com/iplookup.asp?ip=%s&action=2" %(ip)
    headers = {'Host': 'www.ip138.com', 'Connection': 'keep-alive', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'DNT': 1, 'Upgrade-Insecure-Requests': 1, 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-Mode': 'navigate', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Cookie': 'ASPSESSIONIDASDRCTQS=LJOHHGEDLEBEOGADDGALNNJO'}

    req = request.Request(url=index_url, headers=headers)
    start = False
    try:
        with request.urlopen(req) as f:
            data = f.read().decode("gb2312", "ignore").split("\r\n")
            for line in data:
                if line.find("navigator.userAgent") != -1:
                    start = True 

                if start:
                    if line.find("<div class=\"wrapper\">") != -1:
                        break 

                    m = re.findall(r"\"ASN归属地\":\"(.+?)\",", line)
                    if m:
                        return m
    except Exception as e:
        print(e)

def get_ip_region(ip):
    searcher = Ip2Region("ip2region.db")
    #data = searcher.binarySearch(ip)
    #data = searcher.memorySearch(ip)
    data = searcher.btreeSearch(ip)
    region = data["region"].decode('utf-8')
    searcher.close()
    return [region]

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-06-21 21:33:29  更:2022-06-21 21:34:14 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 14:09:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码