Windows Azure のログをおさらい
Windows Azure のログのハンドリングはめんどうですよね。
とはいえ、運用においてはログハンドリングなしでまともな運用ができるはずもなく、改めておさらいしてみました。
というのも、SDK 1.3 でIISログの転送に関する問題が発生したため、そのままほったらかしにしていたのですが、SDK 1.4 で解決したとうので、その確認もかねてというわけです。
が、
まず、肝心のSDK 1.4 のインストールでハマってしまいました。
SDK 1.3 + VS Tool がインストールされている状態では、SDK 1.4 のみをインストールするか、全てをアンインストールしてVSCloudservice.exeを実行すべきらしいのですが、私は、何も読まず、VSCloudservice.exeを実行してしまい、うまくUpdateできていない状態に陥ってしまいました(IISログ転送の問題は少なくとも解決されない状態でした)。
ご注意ください。
さて、キチンと準備できたところで、ほんとにおさらい。
まず、Azure で取れるログには、
- トレースログ
- 診断インフラのログ
- イベントログ
- IISのログ
- パフォーマンスカウンタ
- カスタムログファイル
- アプリケーションダンプ
- Failed Request Trace ログ(IIS失敗要求ログ)
があります。
(私はここの情報をとりあえず参考にしました)。
私が日常的に使うのは1~5なので、ここではまずそれについて整理してみます。
といいつつ、7、8はIISのログを取ると同時とれますし、6はその応用なだけで、後で触れます。
Azure 上のログは、インスタンス上に仮保存されているものを、Storageに転送した後、利用するという運用形式が標準となっており、通常のWindows Server 上でのログ運用とは大きくことなります(RemoteDesktopで見るというのは今回は無し)。
そしてログの種類により、標準で取得(仮保存)されているものと、そうでないものが存在したり、それらを転送する先(Storage)も違っていたりとなかなかクセのあるものになっています。
それぞれの特性は、こちらで確認できます。
Azure のログハンドリングにおいて1つ共通なことがあるとすれば、どのログにせよ、
Storage に転送しなければならない
ということでしょうか。
そして、その転送は、DiagnosticMonitorというエージェント的な機能が担います。
そのため、Azure におけるログハンドリングの最初の1歩は、DiagnosticMonitor をハンドリングすることになります。
では、早速、DiagnosticMonitorに命令して、ログをStorageに転送させるコードを書いてみます。
VSで、WebRoleプロジェクトを作成し、その中のWebRole.csのOnStart()に下記コードを記述します。なお、ここでは、ひとまず、Storage Emulator(ローカル) 上での動作確認を前提とします。
ログを転送するには、各種ログ(ここでは、前述の1~5)毎に転送する間隔を指定することが基本となります。
オンデマンド転送も可能とよく書いているのですが、おそらく、インスタンスの仮保存場所から、それぞれのログを取得するコードを書くという意味なのではと最近思ってきました。
//構成を取得
var config = DiagnosticMonitor.GetDefaultInitialConfiguration();
/////////////
// 1.トレースログ
config.Logs.ScheduledTransferPeriod = System.TimeSpan.FromSeconds(30);
// 2.診断インフラログ
config.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = System.TimeSpan.FromSeconds(30);
// 3.イベントログ
config.WindowsEventLog.ScheduledTransferPeriod = System.TimeSpan.FromSeconds(30);
// 4.IIS通常ログ
config.Directories.ScheduledTransferPeriod = System.TimeSpan.FromSeconds(30);
// 5.パフォーマンスカウンタ
config.PerformanceCounters.ScheduledTransferPeriod = System.TimeSpan.FromSeconds(30);
/////////////
//モニタスタート
DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", config);
やっていることは、まずconfigを取得し、各ログの種類に応じてStorageにコピーする間隔を設定してやっているだけです(ここでは30秒)。
いろいろ書いていますが、赤字部分以外、基本的な構成は同じなことがわかります。
で、DiagnosticMonitor.Start() により、ログの転送が有効になります。
各種ログは、それぞれ、
- WADLogsTable(Table)
- WADDiagnosticInfrastructureLogsTable(Table)
- WADWindowsEventLogsTable(Table)
- wad-iis-logfiles(Blob)
- WADPerformanceCountersTable(Table)
- 指定したBlobコンテナ(Blob)
- wad-crash-dumps(Blob)
- wad-iis-filedreqlogfiles(Blob)
に転送、保存されます。これらはAzureにより自動的に生成されるため、あらかじめ作成する必要はありません。
上記コードを書いた段階で、一度、実行(F5)してみます。
標準で自動生成されるWeb画面が起動しました。
続いてログを確認してみましょう。Azure Storage Explorer 等でStorageをのぞいてみます。なお、ログの転送を30秒に設定してあるので、30秒以上たってから確認するようにします。
まず、Blob
IISのログを保存するwad-iis-logfilesコンテナが生成されています。wad-control-containerは発行ログ等を記録するAzureによって自動生成されるコンテナなので、ここでは無視します(環境によってはVSdeployというのもできてるかもしれませんが、無視します)。
次に、Tableを見てみます。
診断インフラのログを記録するためのTableであるWADDiagnosticInfrastructureTableが作成されています。WADDDirectoriesTableは、IISのログファイルをコピーしたというログを残すためにAzureにより自動生成されたTableなので、ここでは無視します(逆に、IISのログ転送に失敗していると、このテーブルは作成されません)。
ログ取得コードには5種類のログを取得するコードを書きましたが、どうやら診断インフラのログとIISログの2つしか取得できていないようです。後の3つのログはどうしたのでしょうか?
先ほども少々触れましたが、Azure のログには、
- 設定なしで生成(仮保存)され、コピー対象となるもの
- 設定しないとそもそも生成されないのでコピー対象にもならないもの
の2つが存在しています。TraceログやEventlog、PerformanceCounter等は設定しないと生成されないのでコピーされず、それを保存するBlobやTableも生成されないようです。
では、ログ取得に必要な情報を設定してみます。
Trace ログ
Trace ログは、
System.Diagnostics.Trace.TraceInformation()
などとして、ソースコードの任意の位置でディバッグ情報等を出力することで生成され、転送対象となります。ここでは、Default.aspxのPage_Load()に
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Trace.TraceInformation("なんとか起動しました。");
}
と記述してみました。
EventLog
EventLogは、DiagnosticMonitorのconfig設定時に取得する対象を設定します。
//イベントログ
config.WindowsEventLog.ScheduledTransferPeriod = System.TimeSpan.FromSeconds(30);
config.WindowsEventLog.DataSources.Add("System!*");
config.WindowsEventLog.ScheduledTransferLogLevelFilter = LogLevel.Undefined;
ここでではとりあえず、SystemのEventログを取得するようにしました。また、LogLevelは特にすべてとしました(LogLevelも指定しないと出力されません)。
パフォーマンスカウンタ
PerformanceCounterも、EventLog同様、DiagnosticMonitorのconfig設定時に取得する対象を設定します。
//パフォーマンスカウンタ
config.PerformanceCounters.ScheduledTransferPeriod = System.TimeSpan.FromSeconds(30);
var cpu = new PerformanceCounterConfiguration()
{
CounterSpecifier = @"\Processor(_Total)\% Processor Time",
SampleRate = TimeSpan.FromSeconds(10),
};
config.PerformanceCounters.DataSources.Add(cpu);
ここではCPU合計の負荷を取得するようにしました。
ここで、再度実行してみます。そして、30秒ほどまってStorageをのぞいてみます。
今回追加したログはすべてTableにたまるのでTableをのぞきます。
すると、
- WADLogsTable
- WADWindowsEventLogsTable
- WADPerformanceCountersTalbe
の3つがきちんと追加されています。
クラッシュダンプとIIS失敗要求ログ
ここで、7、8のクラッシュダンプとIISエラーログについても見てみます。
まず、これらのログを取得するためには、
IIS失敗要求ログの場合は、Web.configの設定をこちらにしたがって行います。
また、クラッシュダンプを取得する場合は、
Microsoft.WindowsAzure.Diagnostics.CrashDumps.EnableCollection(true);
とします(こちらを参照のこと)。
あとはIISのログが取得できる状態であれば、取得、転送されます。
どういうことかと言いますと、IISログ、IISエラーログ、クラッシュダンプは所定のディレクトリに保存されるのですが、
config.Directories.~
とすることで、一気にStorageにコピーされます。というか、そもそも、IISログのみを指定するconfigは無く、特定のディレクトリ配下のログをコピーする中に、たまたまIISログが含まれているだけです。
で、特定のディレクトリとは、ローカルでは、<実行ディレクトリ>\directory\DiagnosticStore以下のディレクトリで、実際に開いてみてみると、
となっており、あらかじめそれらしい名前のフォルダがあるかと思います(Azure上では、C:\Resources\directory\DiagnosticStore以下)。なので、クラッシュが起きた時のダンプファイルやIIS失敗要求発生時のログは自動的にこれらのフォルダに蓄積され、config.Directories.~が設定されていれば、そのタイミングで転送される仕組み(のはず)です。
カスタムログ
で、最後?に残った6のカスタムログですが、独自のログファイルを独自に設定したディレクトリにたまるようにしておき、コピー対象のディレクトリとして追加指定することで、上記ロジックでコピーされるようになります。
具体的には、
まず、カスタムログを吐くコードを書きます。
ここではDefault.aspxにボタンを配置し、そこに、簡単なログフィルを吐くコードを書きました。test.logというファイルを吐きます。
なお、このコードを実行するためには、あらかじめ、LocalStrageを定義する必要があります。私はLocalStorage1という名前、容量100MBで定義してみました。
protected void Button1_Click(object sender, EventArgs e)
{
var logfile = "test.log";
var message = "test";
try
{
var ls = RoleEnvironment.GetLocalResource("LocalStorage1");
logfile = Path.Combine(ls.RootPath, logfile);
using (var sw = new StreamWriter(logfile, true))
{
sw.WriteLine("{0} : {1}", DateTime.UtcNow, message);
}
}
catch(Exception ex)
{
}
}
}
次に、本命のコード。
その吐いたディレクトリをコピー対象ディレクトリとしてやります。
//独自ログ
var dconfig = new DirectoryConfiguration()
{
//転送先のBlobの設定
Container = "custom-logs",
DirectoryQuotaInMB = 10,
};
var res = RoleEnvironment.GetLocalResource("LocalStorage1");
dconfig.Path = res.RootPath;
//コピーすべきログが置かれたディレクトリを指定する
config.Directories.DataSources.Add(dconfig);
転送先のBlobコンテナと、転送元のディレクトリをDataSourcesとしてAddしてやることで、IISのログと同様、コピー対象ディレクトリとなります。
これを実行してみましょう。
しばらく様子を観察していると、custom-logsというコンテナが追加され、test.logがコピーされています。カスタムログの転送も確認することができました。
めでたしめでたし。
といかないのがAzureです。
少なくとも、私の環境下においては、これまでのコードをAzure 上に発行しただけえはすんなり動いてはくれませんでした。
私が確認した問題
まず、Azure上のStorageを利用するためには、Account NameとAccount Keyを正しく設定する必要があります。それができている前提で、、、
どうやら、IISのログは転送されるのですが、カスタムを含め、その他のディレクトリの転送は相変わらず、うまくいかないようです。
おそらくここに記述されている問題と同じかなと。
とりあえず、csdefファイルに、
<Runtime executionContext="elevated" />
を追加し、管理者でRoleを実行するのと、
<Sites>
~
</Sites>
を削除することで動いたのですが・・・(もしかするとカスタムがOKになるとIISがだめかも・・・)。
とりあえず、今回はここまで。