如何通过阅读,清洁和改善性能问题来改善分析R中的日志文件?

时间:2016-12-22 10:48:33

标签: r performance logfile

现在的任务是尝试提取一些数据用于分析,报告和从特定于应用程序的日志文件进行建模。这些文件的挑战在于它们具有某种“半结构化”性质,以及不同大小(几千字节到几兆字节),并且结构无法改变。

在分析了相当多的这些日志文件后,可以确定四个主要类别的条目。

  • java异常/错误消息(纯文本;分布在几个相邻的行中);
  • 状态消息(第一个条目结构化,后续条目明文分布在几个相邻的行中);
  • 标记/ xml代码(第一个条目结构化,后续条目明文分布在几个相邻的行中);
  • 状态消息(结构化;分布在几个(不一定是)相邻行)。

日志文件的结构化部分包含如下所示的列。

  • 日期;
  • 时间;
  • 参考编号;
  • 类;
  • 端点;
  • 描述/文本。

实施例

<Date> <Time> <RefNo> <Class> <Endpoint> <Description>
2016-12-20 04:04:04.004 12345678 [my.java.class1] (host1-001) start pattern #1
2016-12-20 04:04:04.014 12345678 [my.java.class1] (host1-001) pattern #1-2
2016-12-20 04:04:04.104 12345679 [my.java.class1] (host1-001) pattern #1-3
2016-12-20 04:04:05.004 12345680 [my.java.class2] (host1-001) pattern #1-4
2016-12-20 04:04:06.004 12345681 [my.java.class2] (host1-001) end pattern #1
2016-12-21 05:05:04.005 12389741 [my.java.class3] (host2-003) start pattern #2
2016-12-21 05:05:04.016 12390000 [my.java.class3] (host2-003) pattern #2-2
2016-12-21 05:05:04.108 12390001 [my.java.class4] (host2-003) pattern #2-3
2016-12-21 05:05:04.110 12389741 [my.java.class7] (host3-004) start pattern #3
2016-12-21 05:05:04.115 12390000 [my.java.class7] (host3-004) pattern #3-2
2016-12-21 05:05:05.007 12390002 [my.java.class5] (host2-003) pattern #2-4
2016-12-21 05:05:06.003 12390010 [my.java.class6] (host2-003) end pattern #2
2016-12-21 05:05:06.012 12390010 [my.java.class8] (host3-004) end pattern #3

每个 *状态序列* 以特定的 *开始模式* 开头,随后以相应的 *结尾 - 但不一定相邻 - 结束图案* 。每当关注特定的 *状态序列* 时,保持时间顺序至关重要,同时选择匹配(相同) * *端点

仔细查看各种结构化状态消息的 * description / test * 可以发现20个不同的 *模式序列* ,每个都需要合并并转换为包含一系列变量的单行观测。

预期的目标结构包括以下变量:

  • 时间戳(格式为yyyy-mm-dd hh:mm:ss.tsec);
  • 参考编号;
  • 状态;
  • 类;
  • 端点;
  • 租客;
  • 产物;
  • 服务电话;
  • flag 1;
  • flag 2;
  • flag 3;
  • flag 4;
  • ip address 1;
  • ip address 2;
  • 总时间(以分钟为单位);
  • 时间1(以毫秒为单位);
  • 时间2(以毫秒为单位);
  • 时间3(以毫秒为单位);
  • 长度;
  • 文件名;
  • 文件大小;
  • 元数据大小;
  • 返回值;
  • 错误文字;
  • 记。

通过过滤条目并应用于相关模式,所需信息将从 *状态序列* 的相应行中提取。

由于上述每个 *模式序列* 彼此不同,并且可以在单个日志文件中多次出现,因此每个 *模式序列的特定函数* 已创建。

clnPattern <- function(dt=NULL, cn=NA) {
    pat <- c(startPattern, 
             patternOne,
             patternTwo,
             patternThree,
             patternFour,
             endPattern)
    patLen <- length(pat)
    p <- NULL
    allEP <- NULL
    currEP <- NULL
    rowIdx <- list()
    wipeIdx <- NULL
    seqOk <- NULL
    i <- NULL
    j <- NULL

    tmpDT <- data.table(NULL)
    retDT <- data.table(NULL)

    # cleanse pattern entries
    if (length(dt) > 0) {
        # cycle over each endpoint separately, but only if at
        # least the starting pattern can be found
        if ((length(allEP <- unique(dt[, Endpoint])) > 0) &
            (sum(grepl(pat[1], dt[, Description], ignore.case=TRUE, perl=TRUE)) > 0)) {
            for (currEP in allEP) {
                p <- 1
                if (length(rowIdx[[p]] <- grep(pat[1], 
                    dt[Endpoint == currEP,Description],ignore.case=TRUE,  perl=TRUE)) > 0) {

                    # search for each subsequent pattern respectively
                    for (p in 2:patLen) {
                        rowIdx[[p]] <- grep(pat[p], dt[Endpoint == currEP,
                                            Description],
                                            ignore.case=TRUE, perl=TRUE)
                    } # for

                    # check for pattern sequence & cleanse
                    for (i in 1:length(rowIdx[[1]])) {
                        seqOk <- TRUE
                        wipeIdx <- dt[Endpoint == currEP, RowIdx][rowIdx[[1]][i]]

                        for (p in 2:patLen) {
                            seqOk <- (seqOk &
                                      ((rowIdx[[1]][i] + p - 1) %in% rowIdx[[p]]))
                            wipeIdx <- c(wipeIdx,
                                         dt[Endpoint == currEP, RowIdx][rowIdx[[1]][i] + p - 1])
                        } # for

                        # pattern sequence found
                        if (seqOk) {
                            # consolidate sequence into one single row
                            tmpDT <- dt[Endpoint == currEP][rowIdx[[1]][i]]

                            setColClass(tmpDT)

                            vTimeStamp1=as.POSIXct(strptime(paste(
                                dt[Endpoint == currEP, Date][rowIdx[[1]][i]],
                                   gsub(",", ".",
                                        dt[Endpoint == currEP, Time][rowIdx[[1]][i]],fixed=TRUE)), 
                                "%Y-%m-%d %H:%M:%OS"))
                            vTimeStamp2=as.POSIXct(strptime(paste(
                                dt[Endpoint == currEP, Date][rowIdx[[1]][i] + patLen - 1],
                                   gsub(",", ".",
                                        dt[Endpoint == currEP, Time][rowIdx[[1]][i] + patLen - 1],fixed=TRUE)), 
                                "%Y-%m-%d %H:%M:%OS"))

                            tmpDT[1, `:=`(
                                    TimeStamp=vTimeStamp1,
                                    Var1=getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i]], 
                                        "Description", startPattern, posVar1),
                                    Var2=getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i]], 
                                        "Description", startPattern,  posVar2),
                                    Var3=as.integer(getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i]], 
                                        "Description", startPattern, posVar3)),
                                    Var4=getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i] + 1], 
                                        "Description", patternOne, posVar4),
                                    Var5=getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i] + 2], 
                                        "Description", patternTwo,  posVar5),
                                    Var6=as.double(getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i] + 3], 
                                        "Description", patternThree, posVar6)),
                                    Var7=getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i] + 4], 
                                        "Description", patternThree, posVar7),
                                    Var8=as.double(getFromVariable(dt[Endpoint == currEP][rowIdx[[1]][i] + 5], 
                                        "Description", patternFour,  posVar8)),
                                    TmTotal=as.numeric(vTimeStamp2 - vTimeStamp1)
                                )]

                            # add to resulting data.table
                            retDT <- rbindlist(list(retDT, tmpDT))

                            # mark rows as processed
                            if (length(wipeIdx) > 0) {
                                dt[(RowIdx %in% wipeIdx),
                                    `:=`(Date=NA, Time=NA, RefNo=NA, Class=NA, Description=NA)]
                            } # if
                        } # if
                    } # for
                } # if
            } # for
        } # if

        # re-shape resulting data.table
        if ((length(retDT) > 0) & (length(cn) > 0)) {
            retDT <- retDT[, .SD, .SDcols=cn]
        } # if
    } # if

    # return resulting data.table
    return(retDT)
} # clnPattern

在此函数中,调用另一个用户定义的函数 - * getFromVariable * - 来提取 * descripion / text * 的相关部分,并将它们存储起来远离相应的变量/列。

getFromVariable <- function(dt=NULL, varName="", srchPat="", getPat="") {
    # local variables & constants
    retVal <- NULL
    # search für matching observations/rows, and extract parts from variable
    if ((length(dt) > 0) & (nchar(varName) > 0) & 
        (nchar(srchPat) > 0) & (nchar(getPat) > 0)) {
        # prepare if not a data.table
        if (!is.data.table(dt)) {
            dt <- as.data.table(dt)
            setnames(dt, 1, varName)
        } # if
        # search & extract
        if (varName %in% colnames(dt)) {
            retVal <- trimws(gsub(srchPat, getPat, 
                                  dt[grep(srchPat, 
                                          dt[, varName, with=FALSE][[1]], 
                                          ignore.case=TRUE, perl=TRUE), 
                                     varName, with=FALSE][[1]], 
                                  ignore.case=TRUE, perl=TRUE))
        } # if
    } # if
    # return result vector
    return(retVal)
} # getFromVariable

此功能基本上执行两项任务:

  • 搜索,合并&amp;提取相关位&amp;来自 * dt * data.table;
  • 的bobs
  • 通过将一些变量设置为 *“NA”* 来标记 * dt * data.table中如此处理的行。

这样提取的数据将作为 * data.table * 返回到父级。父级 - 处理完所有已定义的 *模式序列* 后,将从原始 * dt *中删除所有标记的( * NA * )行 data.table,以及将每个返回的特定于模式的data.tables组合成一个单独的,组合的(实际数据分析和建模的基础)。

缺乏对 * R * * data.tables * 的更全面的洞察力,所采取的方法之一是促进 * for-loops * ,充分意识到应尽可能防止这样的车辆被部署。

处理几千字节的日志文件只需几秒钟,但只要进入Mbytes领域,处理时间就会急剧增加,最多可达几分钟。由于为一个日志文件处理了20种不同的模式,平均每个日志文件的平均总时间约为1小时。

我有兴趣学习的是我可以改进所采用的方法,尽可能选择,也许回到绘图板,以便更好地掌握 * R * * data.tables * ,以及显着缩短处理时间,内存使用和性能。

- Sil68

0 个答案:

没有答案