如何配置 Apache 以使虚拟主机的 access.log 或 error.log 始终保持打开?

如何配置 Apache 以使虚拟主机的 access.log 或 error.log 始终保持打开?

我想减少 VPS 上打开的文件数量。使用 lsof 时,我注意到 Apache 始终为服务器上托管的每个域保持 access.log 和 error.log 处于打开状态。

有没有什么办法可以改变这种行为?

答案1

打开许多文件通常不是问题。有一个系统限制,您可以使用命令检查sysctl fs.file-max- 在我的 CentOS 6 系统上,4GB RAM 是 382299,应该足够了,而在我启动的 256MB VM 上,它是 23539,这可能有点太少了。但您可以轻松增加此限制,例如通过添加/etc/sysctl.conf

fs.file-max = 500000

然后运行sysctl -p或重新启动。

您可以编写一个程序,每次从 stdin 接收到数据时,打开、写入、关闭日志文件,并像这样使用它:

CustomLog "||open-write-close /var/log/httpd/access_log" common

但效率不高。而且也不容易,因为它需要使用异步 IO。


我用 C 语言编写了一个程序来实现这个功能:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <limits.h>

int outfd;

int main(int argn, char* argv[])
{
    if (argn != 2) {
        fprintf(stderr, "Usage %s [output_file]\n", argv[0]);
        return 1;
    }

    {
        long stdinflags = fcntl(0,F_GETFL);
        if ( stdinflags == -1 ) {
            perror("fcntl: Can't read stdin status");
            return 2;
        }
        if ( fcntl(0,F_SETFL,stdinflags|O_NONBLOCK) == -1 ) {
            perror("fcntl: Can't set stdin to non-blocking mode");
            return 2;
        }
    }


    do {
        #define BUFSIZE PIPE_BUF
        char buf[BUFSIZE];
        ssize_t bytesread = read(0, buf, BUFSIZE);

        {
            fd_set select_fdset;
            FD_ZERO(&select_fdset);
            FD_SET(0, &select_fdset);
            if ( select(1, &select_fdset, NULL, NULL, NULL) == -1 ) {
                if ( errno != EINTR ) {
                    perror("select");
                    return 2;
                }
            };
        }
        if ( bytesread==-1 ) {
            perror("Can't read from stdin");
            return 2;
        }
        if ( bytesread == 0 ) break;
        outfd = open(argv[1],O_WRONLY|O_APPEND|O_CREAT);
        if ( outfd < 0 ) {
            fprintf(stderr, "Can't open file \"%s\": %s\n", argv[1], strerror(errno));
            return 2;
        }
        do {
            if ( write(outfd, buf, bytesread) == -1 ) {
                fprintf(stderr, "Can't write to file \"%s\": %s\n", argv[1], strerror(errno));
                return 2;
            };
            bytesread = read(0, buf, BUFSIZE);
            if ( bytesread==-1 ) {
                if ( errno==EAGAIN ) break;
                perror("Can't read from stdin");
            }
        } while ( bytesread>0 );
        if ( close(outfd) != 0) {
            fprintf(stderr, "Can't close file \"%s\": %s\n", argv[1], strerror(errno));
            return 2;
        }
    } while ( 1 );
    return 0;
}

答案2

如果你有大量的虚拟主机,并且有单独的访问日志文件,我建议将所有内容记录到一个文件中(是​​的,消除每个虚拟主机中的 CustomLog),然后使用分割日志文件将它们分开。您可以使用日志解析脚本,来解析 DNS 名称。

分割日志文件工作,您需要将 CustomLog 中的第一列设置为 ServerName。

相关内容