Объединить многострочное сообщение из файла журнала в одну строку в R - PullRequest
1 голос
/ 15 марта 2019

Как можно объединить несколько строк файла журнала в 1 строку кадра?

ADDED ONE LINE - Пример файла журнала с 4 строками:

[WARN ][2016-12-16 13:43:10,138][ConfigManagerLoader] - [Low max memory=477102080. Java max memory=1000 MB is recommended for production use, as a minimum.]
[DEBUG][2016-05-26 10:10:22,185][DataSourceImpl] - [SELECT mr.lb_id,mr.lf_id,mr.mr_id FROM mr WHERE  ((                            mr.cap_em >
 0 AND             mr.cap_em > 5
 ))  ORDER BY mr.lb_id, mr.lf_id, mr.mr_id]
[ERROR][2016-12-21 13:51:04,710][DWRWorkflowService] - [Update Wizard - : [DWR WFR request error:
workflow rule = BenCommonResources-getDataRecords
    version = 2.0
    filterValues = [{"fieldName": "wotable_hwohtable.status", "filterValue": "CLOSED"}, {"fieldName": "wotable_hwohtable.status_clearance", "filterValue": "Goods Delivered"}]
    sortValues = [{"fieldName": "wotable_hwohtable.cost_actual", "sortOrder": -1}]
Result code = ruleFailed
Result message = Database error while processing request.
Result details = null
]]
[INFO ][2019-03-15 12:34:55,886][DefaultListableBeanFactory] - [Overriding bean definition for bean 'cpnreq': replacing [Generic bean: class [com.ar.moves.domain.bom.Cpnreq]; scope=prototype; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file:/D:/Dev/404.jar!/com/ar/moves/moves-context.xml]] with [Generic bean: class [com.ar.bl.bom.domain.Cpnreq]; scope=prototype; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file:/D:/Dev/Tools/Tomcatv8.5-appGit-master/404.jar!/com/ar/bl/bom/bl-bom-context.xml]]]

(См. Репрезентативную 8-строчную выдержку в https://pastebin.com/bsmWWCgw.)

Структура чистая:

[PRIOR][datetime][ClassName] - [Msg]

, но сообщение часто многострочное, в скобках может быть несколько скобоксамо сообщение (даже завершающее ...), или ^ M переводы строк, но не обязательно ... Это затрудняет синтаксический анализ. Не знаю, с чего начать ...

Итак, чтобы обработать такой файл и иметь возможностьпрочитайте это примерно так:

#!/usr/bin/env Rscript

df <- read.table('D:/logfile.log')

нам действительно нужно, чтобы это слияние строк происходило первым. Как это возможно?

Цель - загрузить весь файл журнала для создания графики, анализ (вычеркивание материала) и, в конечном итоге, запись его обратно в файл, поэтому, если возможно, следует сохранять переводы строки для соблюдения исходного форматирования.

Ожидаемый кадр данных будет выглядеть следующим образом:

PRIOR   Datetime              ClassName             Msg
-----   -------------------   -------------------   ----------
WARN    2016-12-16 13:43:10   ConfigManagerLoader   Low max...
DEBUG   2016-05-26 10:10:22   DataSourceImpl        SELECT ...

И, в идеале,Опять же, это должно быть выполнимо непосредственно в R (?), чтобы мы могли «обработать» файл живого журнала (открытый в режиме записи серверным приложением), «а-ля tail -f».

1 Ответ

0 голосов
/ 15 марта 2019

Это довольно злая бомба Регекс.Я бы порекомендовал использовать пакет stringr, но вы могли бы сделать все это с помощью функций стиля * 1002.

library(stringr)

str <- c(
  '[WARN ][2016-12-16 13:43:10,138][ConfigManagerLoader] - [Low max memory=477102080. Java max memory=1000 MB is recommended for production use, as a minimum.]
  [DEBUG][2016-05-26 10:10:22,185][DataSourceImpl] - [SELECT mr.lb_id,mr.lf_id,mr.mr_id FROM mr WHERE  ((                            mr.cap_em >
   0 AND             mr.cap_em > 5
   ))  ORDER BY mr.lb_id, mr.lf_id, mr.mr_id]
  [ERROR][2016-12-21 13:51:04,710][DWRWorkflowService] - [Update Wizard - : [DWR WFR request error:
  workflow rule = BenCommonResources-getDataRecords
      version = 2.0
      filterValues = [{"fieldName": "wotable_hwohtable.status", "filterValue": "CLOSED"}, {"fieldName": "wotable_hwohtable.status_clearance", "filterValue": "Goods Delivered"}]
      sortValues = [{"fieldName": "wotable_hwohtable.cost_actual", "sortOrder": -1}]
  Result code = ruleFailed
  Result message = Database error while processing request.
  Result details = null
  ]]'
)

Используя регулярное выражение, мы можем разбить каждую строку, проверив упомянутый вами шаблон.Это регулярное выражение проверяет наличие [, за которым следует любой символ перевода строки, либо перевода строки, либо символа возврата каретки, за которым следует [.Но сделать это ленивым (не жадным) способом, используя *?.Повторите это 3 раза, затем проверьте на -.Наконец, проверьте наличие [, за которым следуют любые символы или группы, включающие информацию в квадратных скобках, а затем ].Это полный рот.Введите его в калькулятор регулярных выражений.Просто не забудьте убрать лишние зазоры (в регулярном выражении используется калькулятор \, но в R \\).

# Split the text into each line without using \n or \r.
# pattern for each line is a lazy (non-greedy) [][][] - []
linesplit <- str %>%
  # str_remove_all("\n") %>%
  # str_extract_all('\\[(.|\\n|\\r)+\\]')
  str_extract_all('\\[(.|\\n|\\r)*?\\]\\[(.|\\n|\\r)*?\\]\\[(.|\\n|\\r)*?\\] - \\[(.|\\n|\\r|(\\[(.|\\n|\\r)*?\\]))*?\\]') %>%
  unlist()

linesplit # Run this to view what happened

Теперь, когда каждая строка разделена, разбейте их на столбцы.Но мы не хотим оставлять [ или ], поэтому мы используем положительный взгляд назад и положительный взгляд в коде регулярного выражения, чтобы проверить, есть ли они, не захватывая их.Да, и, конечно, запишите все между ними.

# Split each line into columns
colsplit <- linesplit %>% 
  str_extract_all("(?<=\\[)(.|\\n|\\r)*?(?=\\])")

colsplit # Run this to view what happened

Теперь у нас есть список с объектом для каждой строки.В каждом объекте есть 4 элемента для каждого столбца.Нам нужно преобразовать эти 4 элемента в фрейм данных, а затем соединить их вместе.

# Convert each line to a dataframe, then join the dataframes together
df <- lapply(colsplit,
  function(x){
    data.frame(
      PRIOR = x[1],
      Datetime = x[2],
      ClassName = x[3],
      Msg = x[4],
      stringsAsFactors = FALSE
    )
    }
  ) %>%
  do.call(rbind,.)

df
#   PRIOR                Datetime           ClassName             Msg
# 1 WARN  2016-12-16 13:43:10,138 ConfigManagerLoader Low max memory=
# 2 DEBUG 2016-05-26 10:10:22,185      DataSourceImpl SELECT mr.lb_id
# 3 ERROR 2016-12-21 13:51:04,710  DWRWorkflowService Update Wizard -

# Note: there are extra spaces that probably should be trimmed,
# and the dates are slightly messed up. I'll leave those for the
# questioner to fix using a mutate and the string functions.

Я оставлю это вам, чтобы исправить лишние пробелы и поле даты.

...