Part 3. Hello World, Windows Azure アプリケーションの開発 その 2

※ 本エントリはその 1 の続きです。

[開発用ファブリック上での動作確認]

引き続き、”CloudService1” プロジェクトをスタートアッププロジェクトに変更し、Ctrl + F5 キーで実行します(※ サーバエクスプローラが pubs.mdf を握っているとエラーが発生するので、デタッチしてから実行してください)。すると、タスクトレイに “Development Fabric” と呼ばれる Windows Azure エミュレータ環境が起動し、この中でアプリケーションが起動します。

image

image

一見すると、先ほどと変わりなく動作しているように見えますが、実際にはかなり異なる環境で Web アプリケーションが動作しています。これについて以下に解説します。

開発用ファブリックのランタイム構成

最終的な運用環境では、このアプリケーションは、ファブリックコントローラによって Windows Azure コンピュートサービスのインフラ上に展開され、複数の仮想マシン(VM, Virtual Machine)が起動します。

image

通常、IIS 7 ではワーカプロセスとして w3wp.exe が利用されますが、Windows Azure コンピュートサービスでは、専用のワーカプロセスとして WaWebHost.exe というものが用意されており、これが起動します。この WaWebHost.exe には、以下の特徴があります。

  • IIS 7 のモジュールをロードして動作するため、内部動作は w3wp.exe とほぼ同じ。
  • 内部では、ASP.NET ランタイムが統合パイプラインモードで動作している。
  • 1 仮想マシン(サーバ)あたり 1 ワーカプロセスが起動する。(=1 つの VM の中で、複数のワーカプロセスが起動することはない)

これに対して、開発用ファブリックでは、運用環境で利用される VM と同じ数だけのホストプロセス(WaWebHost.exe) がローカルコンピュータ内で起動します。

image

image

この開発環境におけるエミュレーション動作の特徴は、以下の通りです。

  • 運用環境と同一のワーカプロセスが複数個使われる。
    この開発用ファブリックでは、1 つのコンピュータ内で、複数のロール、複数の仮想マシンをまとめてエミュレーションする必要があります。このため、開発用マシンの中では、複数の WaWebHost.exe (Worker ロールを使っている場合には WaWorkerHost.exe)が起動する形になります。ワーカプロセスは比較的軽量ですが、とはいえたくさんの VM を利用しようとする場合にはそれなりにマシンのリソース(特にメモリ)を食いますので、注意してください。なお、開発環境と運用環境で利用されるワーカプロセスは基本的にほぼ同じですが、開発環境では 32 ビット版が、運用環境では 64 ビット版が利用される、という点は大きく異なります。.NET のみでアプリケーションを開発している際には問題になりませんが、Unmanaged Code を利用している場合には注意してください。
  • リクエストはロードバランサがいったん受け付ける。
    このワーカプロセスは、クライアントブラウザからのリクエストを直接受け付けるわけではありません。いったん、ロードバランサのエミュレータである DFloadbalancer.exe がリクエストを受け付け、それが各ワーカプロセスにルーティングされる、という仕組みになっています。これは運用環境でも同様で、運用環境でもリクエストはいったんロードバランサが受け付け、それが各マシンにルーティングされる形になります。 
    image  
    image
  • ポート番号は、運用環境で利用する予定のポート番号とはずれることがある。
    上図を見てわかる通り、運用環境では、各 VM マシンに対してプライベート IP アドレスと、乱数によるポートが定められ、フロントエンドのロードバランサからのリクエストがルーティングされる形になっています。これに対して開発用ファブリック(開発環境)では、各ワーカプロセスに対して乱数によるポートが定められ、フロントエンドのロードバランサからリクエストがルーティングされてくる、という形になっています。
    いずれにおいても、ワーカプロセスが直接リクエストを受け付けるわけではないのですが、注意すべき点として、ロードバランサがリクエストを受け付けるポート番号が、開発環境ではずれてしまうことがある、という点に注意してください。例えば、このサンプルアプリケーションを動作させるとブラウザはポート番号 81 上でこのアプリケーションを呼び出します。これは、開発マシン上では、すでにポート番号 80 が IIS 7.5 にアサインされているために使えないからです。このため、DFloadbalancer.exe は 80 のかわりに 81 (次の空きポート)を利用し、これをリスンする、という形になっています。 
    image  

さて、このままだと、このアプリケーションが実際にどのワーカプロセスで処理されているのかがわかりません。そこで、このアプリケーションの Default.aspx.cs ファイルに以下のような修正を加えてください。

  • Microsoft.WindowsAzure.ServiceRuntime への参照設定を加える。
  • using キーワードを追加。(using Microsoft.WindowsAzure.ServiceRuntime;)
  • Page_Load() メソッド内に、インスタンス番号を解決して表示するロジックを追加。(Label3.Text = RoleEnvironment.CurrentRoleInstance.Id;)

image

以上を行った上で、再度 Ctrl + F5 キーで実行すると、Web 画面上にサーバ ID が表示されるようになります。この状態で、リロードやポストバックなどを繰り返していると、ロードバランス機能により、複数のサーバ(ワーカプロセス)に分散処理されることがわかると思います。(※ リロードやポストバックだけでは別サーバインスタンスに振りなおされないケースもありますので、その場合は別の Web ブラウザを起動するなどしてテストしてみてください。)

image image

開発用ファブリックと配置の仕組み

では次に、この開発用ファブリックの動作の仕組みについて、もう少し詳しく見てみましょう。まず、タスクトレイの ”Windows Azure Simulation Environment” のアイコンを右クリックし、メニューから “Show Development Fabric UI” を選択します。これにより、開発用ファブリックの UI が表示されます。

image

image

前述したように、Visual Studio からクラウドサービスプロジェクトを実行すると開発用ファブリックが動作し、その上でアプリケーションが動作するわけですが、この動作はより厳密には以下のようになっています。

  • Visual Studio からクラウドサービスプロジェクトを実行すると、開発用ファブリック上にアプリケーションが展開される。
    この作業を「配置」と呼びます。配置の際には、一意の配置 ID(Deployment ID)が採番されるようになっています。ちなみに配置 ID は、開発環境と運用環境では全くフォーマットが異なっており、以下のようになっています。
    開発環境 → “deployment(21)” のように、一意連番が振られる。
    運用環境 → “6f4d99b8b339413ea3dac24ce71929af” のように、ランダムな GUID 値が振られる。
  • 開発環境では、ローカルマシンの特殊なフォルダにアプリケーションが展開される。
    例えば上記のアプリケーションの場合、”WebApplication1” ロールのインスタンス #0 のアプリケーションは、”C:\Users\nakama\AppData\Local\dftmp\s0\deployment(21)\res\deployment(21).CloudService1.WebApplication1.0” というパスの下側にアプリケーションが展開されて動作しています(このような動作は、ASP.NET 開発サーバによる動作とは全く異なります)。また、このフォルダの下側には、実際に利用する Web アプリケーションの他に、ASP.NET テンポラリファイル、IIS ログ、Diagnostic Monitor によるログファイル、IIS 圧縮キャッシュなど様々なデータが、ロールインスタンス(=運用環境における仮想マシン)ごとに保存されるようになっています。(ちなみに、このフォルダは、下図のように Development Fabric UI から選択して簡単に開くことができます。) 
    image
  • 各ワーカプロセスの状況を、このツールからモニタできる。
    このツールはコンソール出力をモニタできるようになっているので、Diagnostic トレースなどを簡単に見たりすることができるようになっています。また、サービスの停止や、配置したアプリケーションの除去などもこのツール上からできるようになっています。
    ただし、このツールから得られる各サーバ(各ロールインスタンス)の情報については非常に限られており、また、運用環境ではこのモニタツールを使うことはできません。例えば、CPU 稼働率やメモリ利用率の監視、IIS ログの確認などといった内容については、このツールからでは確認できません。これらに関しては、次に述べる Diagnostic Monitor による監視が必要になります。

以上で、基本的な開発用ファブリックの利用方法に関しては終わりです。引き続き、これらのサーバをモニタリングする機能を追加していくことにしましょう。

[Diagnostic Monitor によるアプリケーション監視]

前回 Part 2 のエントリでご紹介したように、Windows Azure コンピュートサービス上の仮想マシンのモニタリングを行うためには、Diagnostic Monitor ランタイムと呼ばれるサービスを利用する必要があります。このサービスは、イベントログやパフォーマンスログ、フラットファイルなどを定期的に監視・データ収集し、Windows Azure ストレージサービスへとデータを転送するために導入されているものです。

image

さて、この Diagnostic Monitor ランタイムでは様々なログデータを転送できるようになっているのですが、実際にはちょっとクセがあります。Diagnostic Monitor ランタイムのドキュメント類を参照すると、以下のようなログファイルが転送できると書かれています。

image

が、この転送は、転送先が Table ストレージになるものと、Blob ストレージになるものとで、仕組みがかなり異なっています

  • 転送先が Table ストレージになっているもの
    ログファイルは、構造を持ったテーブルデータとして、特定の Table ストレージに転送・追記されていきます。
  • 転送先が Blob ストレージになっているもの
    ログファイルは、バイナリファイルとして Blob ストレージに転送・保存されます。

つまり、トレースログやパフォーマンスカウンタのデータは、スキーマを持ったデータとして Table ストレージに分解・整理・転送されるのですが、IIS ログファイルや FREB ログファイルなどは、ただのバイナリファイルとして Blob ストレージに転送される、という形になっています。

※ (参考) 上記の分類では、アプリケーションクラッシュダンプや IIS ログ、FREB ログなどが個別の仕組みとして転送できるように書かれているのですが、実際には、これらはすべて 「特定ディレクトリ下のファイルをまとめて転送する」 という共通の仕組みによりデータ転送が行われています(=仕組みとしては同一で、転送対象となるディレクトリがそれぞれについて指定されている)。このため、例外ログのように独自のログファイル出力機能を持っているアプリケーションの場合には、対象フォルダをこの仕組みに乗せてやれば、独自ログファイルを Azure Blob ストレージに転送させることができるようになります。ただし、独自ログファイルを使う場合、Windows Azure コンピュートサービス上ではセキュリティ制約により、特定のフォルダ(ローカルストレージ(RoleEnvironment.GetLocalResource()))以外への書き込みが認められなくなっているため、この点についてのコード修正が必要になります。ここではこれ以上の深掘りはしませんので、興味がある方は調べてみてください。

※ (参考) また、ローカルで収集されたデータを Windows Azure ストレージサービスに転送する方法は、① 一定時間間隔で自動的に行う方法と、② オンデマンドで指示を出して行わせる方法の 2 通りがあります。②の方法はやや作り込みが必要になるため、ここでは①の方法についてのみ解説します。

さて、Diagnostic Monitor を使うためには、以下の作業が必要になります。

  • Windows Azure ストレージ側の事前準備
    転送先となる Blob ストレージ、Table ストレージなどに、それぞれコンテナやテーブルなどを作成しておく。
  • 収集するログファイルに関する設定方法
    WebRole.cs ファイルの起動処理メソッドの中に、収集方法を指定する。
  • ログファイルの確認方法
    Windows Azure ストレージにアクセスして、データを読み出す。

これらについて順に解説します。

Windows Azure ストレージ側の事前準備

まず、Windows Azure ストレージ側に、データを格納するための Blob コンテナや Table ストレージを作成します。データ転送先となる Blob や Table の名称の多くは固定的に定められていますので、以下のような名称でコンテナやテーブルを作成します。

image

具体的な作業手順は以下の通りです。

  • 開発用ストレージサービスを起動する。
    タスクトレイの ”Windows Azure Simulation Environment” を右クリックし、”Start Development Storage service” を選択して開発用ストレージサービスを起動します。
    image_thumb12
    ※ (参考) この開発用ストレージサービスは、内部的には SQL Server Express Edition のファイルアタッチデータベースを利用しているため、SQL Server Express Edition がインストールされていないとうまく起動しません。
    ※ (参考) 開発用ストレージにゴミがたまってしまった場合には、”Show Development Storage UI” から Reset ボタンを押下すると、簡単に初期状態(空の状態)に戻すことができます。 
    image
  • Blob コンテナやテーブルを作成する。
    次に、コンテナやテーブルを作成します。作成する際は、① ツールを使って手作業でコンテナやテーブルを作成していく方法と、② コンソールアプリケーションなどを使ってコンテナやテーブルを作成する方法の 2 通りがあります。どちらの方法でも構いませんが、ここでは②の方法について示すと、以下のような簡単なコードで作成することが可能です。
    1: using System;
    2: using System.Collections.Generic;
    3: using System.Linq;
    4: using System.Text;
    5:  
    6: // Microsoft.WindowsAzure.ServiceRuntime.dll と Microsoft.WindowsAzure.StorageClient.dll へ参照設定
    7: using Microsoft.WindowsAzure;
    8: using Microsoft.WindowsAzure.StorageClient;
    9:  
   10: namespace ConsoleApplication1
   11: {
   12:     class Program
   13:     {
   14:         static void Main(string[] args)
   15:         {
   16:             // 開発環境の場合(運用環境の場合には適宜コードを修正)
   17:             CloudStorageAccount storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
   18:  
   19:             // 作成するコンテナ、テーブル、キューの名称一覧
   20:             string[] containerNamesToCreate = new string[] {
   21:                 "wad-iis-failedreqlogfiles", "wad-iis-logfiles", "wad-crash-dumps" };
   22:             string[] tableNamesToCreate = new string[] {
   23:                 "WADLogsTable", "WADDiagnosticInfrastructureLogsTable",
   24:                 "WADPerformanceCountersTable", "WADWindowsEventLogsTable", "WADDirectoriesTable" };
   25:             string[] queueNamesToCreate = new string[] { };
   26:  
   27:             // コンテナ、テーブル、キューを作成
   28:             CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
   29:             foreach (string containerName in containerNamesToCreate)
   30:             {
   31:                 CloudBlobContainer blobContainer = blobClient.GetContainerReference(containerName);
   32:                 bool created = blobContainer.CreateIfNotExist();
   33:                 if (created) Console.WriteLine("{0} : コンテナを作成しました。", containerName);
   34:             }
   35:             CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
   36:             foreach (string tableName in tableNamesToCreate)
   37:             {
   38:                 bool result = tableClient.CreateTableIfNotExist(tableName);
   39:                 if (result) Console.WriteLine("{0} : テーブルを作成しました。", tableName);
   40:             }
   41:             CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
   42:             foreach (string queueName in queueNamesToCreate)
   43:             {
   44:                 CloudQueue queue = queueClient.GetQueueReference(queueName);
   45:                 bool result = queue.CreateIfNotExist();
   46:                 if (result) Console.WriteLine("{0} : キューを初期化しました。", queueName);
   47:             }
   48:         }
   49:     }
   50: }

image

ストレージの準備が済んだら、今度は Web アプリケーションに、ログデータ収集と自動転送を行わせるための設定コードを追加します。

収集するログファイルに関する設定方法

Diagnostic Monitor による監視を行うためには、① データをローカルマシン内で収集させるための設定と、② それを Azure ストレージに自動転送させるための設定の 2 つが必要です。収集するログの種類ごとに、設定可能な項目が少しずつ異なりますが、ざっくり書くと、以下のような項目が設定できます。

image

設定を行うためには、以下の作業を行います。

  • Web アプリケーションに WebRole.cs という名前のファイルを追加する。
  • 参照設定として、Microsoft.WindowsAzure.ServiceRuntime, StorageClient, Diagnostics の 3 つの DLL を追加する。
  • using キーワードで、Microsoft.WindowsAzure, StorageClient, ServiceRuntime, Diagnostics の 4 つの名前空間を導入する。
  • WebRole.cs クラスを RoleEntryPoint クラスの派生クラスにする。
  • OnStart() メソッドを実装する。

まずここまでの作業結果を以下に示します。

image

    1: using System;
    2: using System.Collections.Generic;
    3: using System.Linq;
    4: using System.Web;
    5:  
    6: using Microsoft.WindowsAzure.StorageClient;
    7: using Microsoft.WindowsAzure.Diagnostics;
    8: using Microsoft.WindowsAzure.ServiceRuntime;
    9: using Microsoft.WindowsAzure;
   10:  
   11: namespace WebApplication1
   12: {
   13:     public class WebRole : RoleEntryPoint
   14:     {
   15:         public override bool OnStart()
   16:         {
   17:             // ここに初期化処理を実装する
   18:  
   19:             return base.OnStart();
   20:         }
   21:     }
   22: }

そしてこの OnStart() メソッドに、Diagnostic Monitor の初期化処理を記述します。

    1: using System;
    2: using System.Collections.Generic;
    3: using System.Linq;
    4: using System.Web;
    5:  
    6: using Microsoft.WindowsAzure.StorageClient;
    7: using Microsoft.WindowsAzure.Diagnostics;
    8: using Microsoft.WindowsAzure.ServiceRuntime;
    9: using Microsoft.WindowsAzure;
   10:  
   11: namespace WebApplication1
   12: {
   13:     public class WebRole : RoleEntryPoint
   14:     {
   15:         public override bool OnStart()
   16:         {
   17:             // 構成設定ファイルの変更を自動追尾するための処理(詳細は後述)
   18:             CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
   19:             {
   20:                 configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
   21:                 RoleEnvironment.Changed += (sender, arg) =>
   22:                 {
   23:                     if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
   24:                         .Any((change) => (change.ConfigurationSettingName == configName)))
   25:                     {
   26:                         if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
   27:                         {
   28:                             RoleEnvironment.RequestRecycle();
   29:                         }
   30:                     }
   31:                 };
   32:             });
   33:  
   34:             DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration();
   35:  
   36:             // トレースログ (※ web.config への設定も必要)
   37:             dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(2);
   38:             dmc.Logs.ScheduledTransferLogLevelFilter = LogLevel.Warning;
   39:  
   40:             // Diagnostic Monitor ログ
   41:             dmc.DiagnosticInfrastructureLogs.ScheduledTransferPeriod = TimeSpan.FromMinutes(2);
   42:             dmc.DiagnosticInfrastructureLogs.ScheduledTransferLogLevelFilter = LogLevel.Critical;
   43:  
   44:             // イベントログ
   45:             dmc.WindowsEventLog.DataSources.Add("Application!*");
   46:             dmc.WindowsEventLog.DataSources.Add("System!*");
   47:             dmc.WindowsEventLog.ScheduledTransferPeriod = TimeSpan.FromMinutes(2);
   48:             dmc.WindowsEventLog.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
   49:  
   50:             // パフォーマンスカウンタ
   51:             dmc.PerformanceCounters.DataSources.Add(
   52:                 new PerformanceCounterConfiguration()
   53:                 {
   54:                     CounterSpecifier = @"\Processor(_Total)\% Processor Time",
   55:                     SampleRate = TimeSpan.FromSeconds(60)
   56:                 });
   57:             dmc.PerformanceCounters.ScheduledTransferPeriod = TimeSpan.FromMinutes(2);
   58:  
   59:             // カスタムファイルログ (※ IIS ログ, FREB ログ, クラッシュダンプは設定済み)
   60:             dmc.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
   61:  
   62:             // Diagnostic Monitor をスタートさせる
   63:             DiagnosticMonitor.Start("DiagnosticsConnectionString", dmc);
   64:  
   65:             return base.OnStart();
   66:         }
   67:     }
   68: }

 

 

コードの意味については見れば概ねわかると思いますが、基本的には、① データ収集に関する条件と、② データ自動転送に関する条件を指定しています。おおまかにいえば、データ転送に関する条件を .ScheduledTransferPeriod プロパティや .ScheduledTransferLogLevelFiler プロパティにより設定し、その他の .DataSource プロパティなどでデータ収集条件を設定します。ここでは 2 分間隔でデータ転送する形にしましたが、実際のシステムでは転送間隔はもう少し長くてもよいでしょう。

※ (参考) データの転送間隔については、むやみに短くしないことをおすすめします。これは、転送間隔をむやみに短くすると、それだけシステムに負荷がかかってしまうためです。「仮想マシンがクラッシュするとログデータが吹き飛ぶので、極力転送間隔を短くしておきたい」と考える人もいると思います(し、それは確かに正しいのです)が、通常のシステムでも、ローカルマシンに出力されたファイルを監視マシンに吸い上げるときにはある程度の時間間隔を置いてチェックおよび吸出しを行っているはずです。それと同様に考えればよいでしょう。

さて、上記のサンプルコードについては、いくつかの注意点があります。要点を説明すると、以下の通りです。

  • コードの先頭に書かれている、.SetConfigurationSettingPublisher() メソッドは、サービス構成設定の変更を動的に追いかけるためのコードです。が、ここではまだ意味が分からないと思いますので、とりあえず「呪文」だと思っておいていただければ結構です。(詳細はこのあとでまた解説します。)

  • 「トレースログ」と書かれているのは、System.Diagnostics トレース(System.Diagnostics.Trace.

    WriteLine() などの命令により出力される Win32 トレースログ)ですが、この機能を使うためには、web.config ファイルに以下の記述を追加する必要があります。このコードを追加することにより、Win32 トレースログの情報が、Azure の Diagnostic Monitor ランタイムの方に転送され、記録されるようになります。

    1: <?xml version="1.0"?>
    2: <configuration>
    3:  
    4:   ... (前略) ...
    5:  
    6:   <system.diagnostics>
    7:     <trace>
    8:       <listeners>
    9:         <add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
   10:             name="AzureDiagnostics" />
   11:       </listeners>
   12:     </trace>
   13:   </system.diagnostics>
   14:  
   15:   ... (後略) ...
   16:  
   17: </configuration>
  • 「Diagnostic Monitor ログ」とは、Diagnostic Monitor ランタイム自身から発生するログですが、これに関しては必ずフィルタリング条件を設定してください。(少なくとも Warning 以上) Verbose レベルでデータ収集を行うと、大量(数秒間に数十エントリ)のデータが出力されてとんでもないことになります;。基本的には Critical などに設定しておけば十分でしょう。
  • (参考) イベントログのデータ収集・転送に関しては、運用環境では問題なく動作するのですが、開発環境ではどうもうまく動作しないようです。私自身、原因がどこにあるのかまだわかっていませんが、運用環境では動くので、開発環境で動作しないことについては目をつぶっていただけると助かります;。(と、つぶやいてみる;。)
  • 最後の DiagnosticMonitor.Start() メソッドによって Diagnostic Monitor ランタイムを起動していますが、このメソッドの第 1 パラメータ(ここでは “DiagnosticsConnectionString”)で、転送先となる Windows Azure ストレージへの接続情報を設定しています。この接続情報は、クラウドサービスプロジェクト側の “Settings” セクションに設定されており、既定では “UseDevelopmentStorage=true” (開発ストレージにログ情報を転送する)という設定になっています。(運用環境に持っていく場合には、この設定値を、本番環境の Windows Azure ストレージサービスへの接続文字列に書き換えます。)

image

※ (参考) 最後の Windows Azure ストレージサービスへの接続文字列情報に関してですが、以下のようなコードを使えば、直接、データ転送先のストレージを指定することができます。が、この方法を使うと、環境切り替えが大変になるため、通常は、上記のような方法を使って、構成設定情報として接続先ストレージの情報を切り出しておきます。

    1: // CloudStorageAccount クラスを使って指定する方法もあるが、環境切り替えが大変。
    2: CloudStorageAccount storageAccount = new CloudStorageAccount(
    3:     new StorageCredentialsAccountAndKey("devstoreaccount1",
    4:      "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="),
    5:     new Uri("https://127.0.0.1:10000/devstoreaccount1"),
    6:     new Uri("https://127.0.0.1:10001/devstoreaccount1"),
    7:     new Uri("https://127.0.0.1:10002/devstoreaccount1"));
    8: DiagnosticMonitor.Start(storageAccount, dmc);

以上で設定は完了です。この状態で、アプリケーションを実行してみてしばらく使い、その後、放置(5 分程度)してみてください。これにより、ログデータが適宜 Azure ストレージに転送されているはずです。

ログファイルの確認方法

最後に、転送されたログファイルを確認してみることにします。一番手っ取り早い方法は、各種のツールを使って Windows Azure ストレージに接続し、その中を確認してしまう方法です。残念ながら現在のところは Microsoft の便利なオフィシャルツールが存在しないため(っつーか誰か作ってほしい....とつぶやいてみる;)、3rd party 製のツール(例えば Cerebrata 社の Cloud Storage Studio など)を使う必要があります。

ですが、このようなツールを入手したり使ったりすることが困難な場合には、コンソールアプリケーションなどを書いておくと便利でしょう。ここでは、Azure ストレージに保存された IIS のログファイルをダウンロードするためのコードを以下に示します。

    1: using System;
    2: using System.Collections.Generic;
    3: using System.Linq;
    4: using System.Text;
    5:  
    6: using Microsoft.WindowsAzure;
    7: using Microsoft.WindowsAzure.StorageClient;
    8: using System.IO;
    9:  
   10: namespace ConsoleApplication2
   11: {
   12:     class Program
   13:     {
   14:         static void Main(string[] args)
   15:         {
   16:             // Diagnostic Monitor のログデータ一括転送
   17:             // 開発環境の場合(運用環境の場合には適宜コードを修正)
   18:             CloudStorageAccount storageAccount = CloudStorageAccount.DevelopmentStorageAccount;
   19:  
   20:             // 転送先となるローカルパス
   21:             string localRootPath = @"C:\temp\" + DateTime.UtcNow.ToString("yyyyMMdd_HHmmss");
   22:             bool willFileDelete = true; // 転送したファイルを消すか否か
   23:  
   24:             // ① Blob データのダウンロード
   25:             CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
   26:             foreach (string containerName in new string[] {
   27:                 "wad-control-container", "wad-iis-failedreqlogfiles", "wad-iis-logfiles", "wad-crash-dumps" })
   28:             {
   29:                 CloudBlobContainer blobContainer = blobClient.GetContainerReference(containerName);
   30:                 var blobs = blobContainer.ListBlobs(new BlobRequestOptions() { UseFlatBlobListing = true });
   31:  
   32:                 foreach (var blob in blobs)
   33:                 {
   34:                     CloudBlob cb = blobContainer.GetBlobReference(blob.Uri.AbsoluteUri);
   35:                     string localFilePath = localRootPath + @"\Blob" + blob.Uri.PathAndQuery.Replace('/', '\\');
   36:                     Console.WriteLine(blob.Uri.AbsoluteUri + " → " + localFilePath);
   37:                     Directory.CreateDirectory(localFilePath.Substring(0, localFilePath.LastIndexOf('\\')));
   38:                     cb.DownloadToFile(localFilePath);
   39:                     if (willFileDelete) cb.Delete();
   40:                 }
   41:             }
   42:         }
   43:     }
   44: }

実行すると、Windows  Azure ストレージに蓄積された IIS ログを、ローカルマシンにダウンロードすることができるようになります。あとはこれを Excel や各種のログ解析ツールなどに読み込ませて分析していただければよいでしょう。

image

というわけで Windows Azure コンピュートサービスの監視方法について解説しましたが、これらの説明からわかるように、現時点では、Azure コンピュートサービスの監視 API は比較的剥き出しのような状態で、残念ながら、使いやすいツール類が充実しているとはちょっと言い難い状況です。3rd party 製ツールとしては Cerebrata 社の Azure Diagnostics Manager などのツールが出てきていますが(デモ見る限りは恐ろしくよくできてますねこれ....;)、このあたりについては今しばらくは手作業で頑張らないといけなさそうな気配です。ただ、Diagnostic Monitor ランタイムの基本動作やその考え方については、今のうちにきっちり理解しておいてよいと思いますので、一度はぜひ触ってみてください。

ではいよいよ、ここまで作成したアプリケーションを、Windows Azure の本番環境に配置していきましょう。(その 3 に続く…)