
複数のエントリがありますイベント非常に大きなログファイルでは、ログ私は2つのことをしたい。イベントログファイル内のエントリ:
- このような各エントリの出現回数を数えます。(これは必須要件ではありませんが、あれば便利です。)
- 実際のエントリを別のファイルに抽出し、後で調べます。
典型的なイベントエントリは次のようになります。イベントエントリの間には他のテキストが入ります。以下の例では、イベント最初のエントリには 2 つのDataChangeEntry
ペイロードが含まれ、2 番目のエントリには 1 つのDataChangeEntry
ペイロードが含まれます。
Data control raising event :DataControl@263c015d[[
#### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1. beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58. beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
Filter/Collection Id : 0
Collection Level : 0
Sequence Id : 616
ViewSetId : PatternMatch.LegendTimeAxis_V1_0_SN49
==== DataChangeEntry (#1)
ChangeType : UPDATE
KeyPath : [2014-06-26 06:15:00.0, 0]
AttributeNames : [DATAOBJECT_CREATED, COUNTX, QueryName]
AttributeValues : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
AttributeTypes : [java.sql.Timestamp, java.lang.Integer, java.lang.String, ]
==== DataChangeEntry (#2)
ChangeType : UPDATE
KeyPath : [2014-06-26 06:15:00.0, 0]
AttributeNames : [DATAOBJECT_CREATED, COUNTX, QueryName]
AttributeValues : [2014-06-26 06:15:00.0, 9, AverageCallWaitingTimeGreateThanThreshold]
AttributeTypes : [java.sql.Timestamp, java.lang.Integer, java.lang.String, ]
]]
someother non useful text
spanning multiple lines
Data control raising event :DataControl@263c015d[[
#### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1. beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58. beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
Filter/Collection Id : 0
Collection Level : 0
Sequence Id : 616
ViewSetId : PatternMatch.LegendTimeAxis_V1_0_SN49
==== DataChangeEntry (#1)
ChangeType : UPDATE
KeyPath : [2014-06-26 06:15:00.0, 0]
AttributeNames : [DATAOBJECT_CREATED, COUNTX, QueryName]
AttributeValues : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
AttributeTypes : [java.sql.Timestamp, java.lang.Integer, java.lang.String, ]
]]
イベント エントリの行数は ==== DataChangeEntry
可変であることに注意してください。また、行数がまったく存在しない場合もあります。これはイベント ペイロードが空であることを示し、エラー状態であるため、このケースも確実に検出する必要があります。
この場合、エントリの出力は複数の行にまたがるため、単純な grep ではうまくいきません。そのため、専門家のアドバイスを求めています。
追伸:
- 私の要件をもう少し明確に述べさせてください。上記のテキスト ブロック全体をそのままキャプチャし、オプションで、そのようなブロックに遭遇したインスタンスの数をカウントしたいと考えています。インスタンスの数をカウントするオプションはあれば便利ですが、必須要件ではありません。
- 問題の解決策が awk を使用することである場合、awk ファイルを保存して再利用したいと思います。したがって、スクリプトを実行する手順も教えてください。私は regex と grep は知っていますが、sed や awk には精通していません。
答え1
これでうまくいくと思います。イベントはevents
ファイルに送られます。メッセージは標準出力に送られます。
このファイルを myprogram.awk に保存します (例):
#!/usr/bin/awk -f
BEGIN {
s=0; ### state. Active when parsing inside an event
nevent=0; ### Current event number
printf "" > "events"
}
# Start of event
/^ *Data control raising event/ {
s=1;
dentries=0;
print "*** Event number: " nevent >> "events"
nevent++
}
# Standard event line
s==1 {
print >> "events"
}
# DataChangeEntry line
/^ *==== DataChangeEntry/ {
dentries ++
}
# End of event
s==1 && /^ *\]\]/ {
s=0;
print "" >> "events"
if(dentries==0){
print "Warning: Event " nevent " has no Data Entries"
}
}
END {
print "Total event count: " nevent
}
さまざまな方法で呼び出すことができます:
myprogram.awk inputfile.txt
awk -f myprogram.awk inputfile.txt
サンプル出力:
Warning: Event 3 has no Data Entries
Total event count: 3
events
作業ディレクトリにあるファイルですべてのイベントをまとめて確認できます。
答え2
非常にシンプルなアプローチは
awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" file
これにより、エントリごとに個別のファイルが作成され、見つかったエントリの数を標準出力に出力します。
説明
NR
は、 内の現在の行番号ですawk
。RS="]]"
レコード区切り文字 (「行」を定義するもの) を に設定します]]
。つまり、各エントリは によって 1 行として扱われますawk
。{print > NR".entry"}
: これは、現在の行 (エントリ) を というファイルに出力します[LineNumber].entry
。したがって、 に1.entry
は 1 番目、2.entry
2 番目などが含まれます。END{print NR" entries"}
: END ブロックは、入力ファイル全体が処理された後に実行されます。したがって、その時点では、NR
処理されたエントリの数が になります。
これをエイリアスとして保存するか、次のようにスクリプトにすることができます。
#!/usr/bin/env bash
awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" "$1"
foo.sh
次に、ターゲット ファイルを引数としてスクリプトを実行します (スクリプトが呼び出され、$PATH 内にあると仮定します)。
foo.sh file
出力ファイル名を微調整することもできます。たとえば、ファイル名を次のようにするには、[date].[entry number].[entry]
代わりに次のようにします。
#!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{print > d"."NR".entry"}END{print NR" entries"}' RS="]]" d="$date" "$1"
上記は、ログ ファイルが「イベント」エントリのみで構成されていることを前提としています。そうでない場合、他の行が存在し、それらの行を無視する必要がある場合は、代わりに以下を使用します。
#!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{
if(/\[\[/){a=1; c++;}
if(/\]\]/){a=0; print > d"."c".entry"}
if(a==1){print >> d"."c".entry"}
}' d="$date" file
あるいは、一言で言えば:
awk '{if(/\[\[/){a=1; c++;}if(/\]\]/){a=0; print > d"."c".entry"}if(a==1){print >> d"."c".entry"}}' d=$(date +%Y%m%d) file