Rのggplot2でWindowsパフォーマンスカウンタを可視化

独特?な形式のWindowsパフォーマンスカウンターのcsv形式ログをRのggplot2で 美しく実用的に、そしてほぼ自動的に可視化しようというお話です。

今まで参加してきた現場で、よくWindowsサーバーのパフォーマンスカウンタのログを CSVで保存して収集しておく。という事が行われていたのですが、それを可視化しようとした時に、 Excelで開いて……グラフ設定して…… というとてもめんどくさい手順を踏むのを見てきました。 しかしこういったExcel運用はご存知の通り以下の問題が発生します。

  • グラフ設定の作業が冗長(項目ごとにグラフに追加したり…)
  • めんどくさいのでそもそも取得する項目の種類も控えめにしてしまう
  • 大きなデータを扱うと重くなるのでサンプル間隔も長めにしてしまう
  • 作る人によって見た目がバラバラ
  • グラフ内の何時何分何秒を示しづらい

といった感じで非常にデータがもったいない上、Excel方眼紙の得意なエンジニア各位は Excelのこういった本来の(?)使い方が苦手な傾向にあるようで、 時間がかかってしまうようです。

以下では、統計分析言語のRと主にggplot2というライブラリを使って、そんなWindowsの パフォーマンスログを項目毎に自動でPDF出力するサンプルを紹介します。

次の機能があります

  • csvに記録されている全項目が出力される(ちょうべんり)
  • 以下2つのPDFを生成

    • 1ページに全項目を標準化した値でプロットしたPDFの生成 → 異常を示す項目があるかないかを確認
    • 1項目1ページのマルチページPDFの生成 → ページめくりで次々項目を確認可能
  • PDFはA4横サイズ -- 印刷も簡単
  • 指定日時に半透明の赤線で縦棒を引く → 障害発生時間などを示せる

RScriptコマンドを使えばスケジュールで定期的に生成する事も可能ですので、 運用の現場などでは定例報告会みたいな日に合わせてセットしておくといいんじゃないでしょうか。 コメントなどは入れられませんので、レポート風にするならRmarkdownやJupyterなどを 使用すると良いと思います。

setwd("~/")
# 変数セット

occured <- as.POSIXct(c("2015-02-12 00:40:23","2015-02-12 00:45:12"))
singlepage_pdf <- "single_page.pdf"
multipage_pdf <- "multi_page.pdf"
pdf_path <- "perf_report.pdf"
input_csv <- "perf.csv"



# 関数セット

parse_metric <- function(x) {
# Windowsパフォーマンスログ(csv)の項目名をパース
# Rの仕様でcsvを読み込んだ時点でカラム名に使えない記号等は処理されるので、
# 例えば
#   \\host_name\Processor(0)\% Processor Time は、
#   X..GMDRW8.Processor.0....Processor.Time   となる
# それらを . で区切って切り貼りし、カラム名として扱いやすい
# 書式に変換する
  xsplit <- strsplit(x,"\\.+")[[1]]
  host_name <- xsplit[2]
  category_ <- xsplit[3]
  metric_ <- xsplit[4:length(xsplit)]
  metric_ <- paste(metric_,collapse="_")
  result_ <- paste(host_name,category_,metric_,sep="_")
  return(result_[[1]])
}

zs <- function(x) {
# ZScore算出関数
    zs <- (x - mean(x)) / sd(x)
    return(zs)
}

generate_plot <- function(d,metric,occured="") {
    gg <- ggplot(d,aes_string(x="DateTime",y=metric)) + 
          geom_line(size=0.5) +
          scale_y_continuous(labels=comma) +
          scale_x_datetime(breaks=date_breaks("1 hour"),
                     labels=date_format("%m/%d %H:%M"))
    if(occured) {
        gg <- gg + geom_vline(xintercept=occured,
                              colour="red",alpha=0.5)
    }
    return(gg)
}

# データ読み込み

csv_ <- read.csv(input_csv)
d_ <- csv_

# カラム名のパース
names_ <- names(csv_)
metrics_ <- paste(lapply(names_,parse_metric))
metrics_[1] <- "DateTime"
names(d_) <- metrics_

# 日時文字列のパース( 02/24/2015 16:23:58 -> 日時型へ )
d_$DateTime <- as.POSIXct(d_$DateTime,format="%m/%d/%Y %H:%M:%S")

d_ <- tbl_df(d_)

metrics_ <- names(d_)[2:length(names(d_))]

# データを標準化して出力。

CairoPDF(paper="a4r",width=11.69,height=8.27,file=singlepage_pdf)
p_ <- melt(d_,.(DateTime))
p_ <- p_ %.% group_by(variable) %.% mutate(value=zs(value))
gg <- ggplot(p_,aes(x=DateTime,y=zs(value),colour=variable)) +
      geom_line(size=0.5) +
      geom_vline(xintercept=occured,colour="red",alpha=0.5)
print(gg)
dev.off()

# PDF出力 - 項目毎に1ページ

CairoPDF(paper="a4r",width=11.69,height=8.27,file=multipage_pdf)
for(m_ in metrics_) {
  print(generate_plot(d_,m_,occured))
}
dev.off()