きな粉もち.net

.NET関連仕事に携わっています。OSSのソースを読んで気がついたことを中心に呟いたりブログに投稿したりしています。最近はUiPathを使ったRPAも研究中。気軽にフォローやツッコミよろしくおねがいします! Gitはここを使っています https://github.com/kinakomotitti

log4net × FileSystemWatcher × 設定ファイルの監視

引き続き、log4netの起動処理の解読をする中で学んだ技術についてまとめていきます。
今回は、System.IO.FileSystemWatcherクラスについてです。

log4netでは、FileSystemWatcherを使って設定ファイルの変更を監視し、変更があった場合設定ファイルを再読み込みするように動作させることができます。

設定方法

この「設定ファイルの変更を監視し、変更検出時に再読み込み」設定を有効/無効にするためには、log4netの呪文の値を変更します。
↓呪文↓

assembly: log4net.Config.XmlConfigurator(Watch = true,ConfigFile =@".\config\log4net.config")]

呪文の設定方法とか読み込みの処理は以下の記事でちょっとまとめてます。
気が向いた時に思い出してくださいw
kinakomotitti.hatenablog.com

呪文のWatchに設定する値をTrueにすることで、この設定が有効になります。

実装

設定ファイルの変更を監視して、変更があったときにファイルを再読み込みする・・・・
さて、どうやって実現しているかをlog4netのコードから確認してみます。

実装は以下のようになっています。(log4net.Core.XmlConfiguratorクラスから抜粋)

public ConfigureAndWatchHandler(ILoggerRepository repository, FileInfo configFile)
{
    	m_repository = repository;
    	m_configFile = configFile;

    	// Create a new FileSystemWatcher and set its properties.
ここ1→	m_watcher = new FileSystemWatcher();
    
    	m_watcher.Path = m_configFile.DirectoryName;
    	m_watcher.Filter = m_configFile.Name;

    	// Set the notification filters
    	m_watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.FileName;

    	// Add event handlers. OnChanged will do for all event handlers that fire a FileSystemEventArgs
ここ2→  m_watcher.Changed += new FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
    	m_watcher.Created += new FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
    	m_watcher.Deleted += new FileSystemEventHandler(ConfigureAndWatchHandler_OnChanged);
    	m_watcher.Renamed += new RenamedEventHandler(ConfigureAndWatchHandler_OnRenamed);

    	// Begin watching.
ここ3→	m_watcher.EnableRaisingEvents = true;

    	// Create the timer that will be used to deliver events. Set as disabled
ここ4→	m_timer = new Timer(new TimerCallback(OnWatchedFileChange), null, Timeout.Infinite, Timeout.Infinite);
}

ここ1:
本日の主役のFileSystemWatcherクラスのインスタンスを生成しています。

ここ2:
ファイルが、変更された、作成された、消された、時に、ConfigureAndWatchHandler_OnChangedメソッドが、
リネームされたときに、ConfigureAndWatchHandler_OnRenamedメソッドが実行されるようにイベントを登録しています。
※ConfigureAndWatchHandler_OnChanged、ConfigureAndWatchHandler_OnRenamedでは、メソッドは別で定義されていますが、処理は同じです。
 上の2つのメソッドでは、”ここ4”で生成しているTimerインスタンスを使って、コールバック関数のOnWatchedFileChangeメソッドを実行させています。
 なお、ファイルが変更された通知が来てから500ミリ秒後に1回だけ実行されるように実装されています。

//TimeoutMillis = 500
m_timer.Change(TimeoutMillis, Timeout.Infinite);

ここ3:
FileSystemWatcherでは、インスタンスをNewするだけではなく、明示的に監視をOnしてあげないといけません。
EnableRaisingEventsプロパティをTrueにすることで、監視を開始することができます。(忘れがち?w)

ここ4:
Timerクラスのインスタンスを作成。
第一引数:A System.Threading.TimerCallback を実行するメソッド。
      → 実行したい処理的な感じ
第二引数:コールバック メソッドで使用される情報を格納したオブジェクトまたは null。
      → 第一引数の引数的な感じ
第三引数:System.Threading.Timeout.Infiniteはタイマーが起動しないようにするために設定する
     0は、タイマーを即時起動させるときに設定する
     それ以外は、指定された時間が経過したのちにタイマーが起動する
      → 遅延時間の設定
第四引数:呼び出しの間の時間間隔。
      → スヌーズ機能的な感じ

FileSystemWatcherについて気を付けること

FileSystemWatcherには、InternalBufferSizeというプロパティがあります。
このInternalBufferSizeは4KB ~ 64KBの範囲で設定できるFileSystemWatcherインスタンス内のメモリバッファです。
4KB以下に値を設定しようとすると、その設定値は破棄され、4KBに設定されるそうです。
このファイルバッファは、システム→コンポーネントAPIとファイルの通知を伝えるときに利用されます。
そのため、一度に大量の変更が生じてこのバッファがいっぱいになってしまった場合は、ファイルの変更情報が失われてしまうことがあります。 ←これこわいですねwバグになりそう。。。
バッファの節約のためにも、
・NotifyFilterプロパティ
・IncludeSubdirectoriesプロパティ
上記2つの設定を適切に行い、不要な変更通知をフィルタ処理する必要があります。
log4netでは、バッファは規定値を使っていますが、NotifyFilterプロパティを変更していました。
FileSystemWatcher.InternalBufferSize プロパティ (System.IO)

まとめ

log4netでWatch=trueを設定すると、FileSystemWatcherが起動され、log4net.configファイルが監視されるよ!
メモリ節約する場合や、設定が頻繁に変わらないから・・・って場合は、Falseにしたほうがよさそうですね。
知らず知らずのうちに、Trueにしちゃってた気がする・・・

なお、FileSystemWatcherには、ネットワークドライブ経由の条件下でバグるらしいので、利用するときは気をつけてください!
FileSystemWatcher doesn’t fire events for monitored network drive after changing InternalBufferSize – Kim Hamilton

もっとFileSystemWatcherクラスについて詳しく知りたい場合は、以下の記事が参考になると思います。
Detecting File Changes with FileSystemWatcher

log4net × System.Attribute × 呪文

log4netのDeep Diveの続きになります。

前回*1に引き続き、log4netを読んでいるうちに知ったCustomAttributeについてまとめます。
今回は、特に設定したCustom Assemblyの情報をどうやって取得するかを中心にまとめます。
以下のように(普通に)Loggerのインスタンスを生成する時のことを考えます。

LogManager.GetLogger("LoggerName");

処理が始まると、なんやかんやでlog4net.Core名前空間のDefaultRepositorySelectorクラスに処理が進みます。
そして、同クラスのConfigureRepositoryメソッドが実行されます。

一部抜粋しました。

private void ConfigureRepository(Assembly assembly, ILoggerRepository repository)
{
		if (assembly == null)
		{
			throw new ArgumentNullException("assembly");
		}
		if (repository == null)
		{
			throw new ArgumentNullException("repository");
		}
		object[] configAttributes = Attribute.GetCustomAttributes(assembly, typeof(log4net.Config.ConfiguratorAttribute), false);
               ・・・
}

この最後の行のように、AttributeクラスのGetCustomAttributesメソッドを利用することで、
設定したCustom Assemblyの中にある”第二引数で指定した型の情報”を取得することができます。

log4netでは、利用するときに以下の呪文を唱えるので、log4net.Config.ConfiguratorAttributeクラスを継承しているXmlConfiguratorクラスのインスタンスを取得することができます。

呪文↓

[assembly: log4net.Config.XmlConfigurator(Watch = true,ConfigFile =@".\config\log4net.config")]

取得したAttributeの配列はループでそれぞれConfigureメソッドを実行しながら処理されていきます。

foreach(log4net.Config.ConfiguratorAttribute configAttr in configAttributes)
{
	if (configAttr != null)
	{
	 try
	 {
	   configAttr.Configure(assembly, repository);
	 }
	 catch (Exception ex)
	 {
 	   LogLog.Error(declaringType, "Exception calling ["+configAttr.GetType().FullName+"] .Configure method.", ex);
	 }
	}
}


複数呪文を唱えておけば、それだけ設定してくれるということでしょうか・・・
どういうときに複数呪文唱えるか想像ができませんが・・・
今はMPが足りないので、唱えられないようですw

なお、log4netで定義されているConfiguratorAttributeクラスを継承しているクラスは以下の2つです
・SecurityContextProviderAttribute
・XmlConfigurator


まとめ!

属性情報を読み取りたいときは、System.Attributeクラスを利用します!
log4netの設定ファイルの構成処理にも利用されています。
忘備録ですが、以下のように実装すると、アセンブリバージョン情報を取得することができます。

var version = System.Attribute.GetCustomAttributes(System.Reflection.Assembly.GetCallingAssembly(), typeof(System.Reflection.AssemblyFileVersionAttribute));

*1:ここに脚注を書きます kinakomotitti.hatenablog.com

log4net × Assemblyファイルの設定 × 属性の名前付きパラメータ

久しぶりのlog4netのDeep Diveの続きになります。
今回は、log4netを読んでいるうちに知ったCustomAttributeの設定方法、定義方法についてまとめます。

log4netを利用する時、logの出力設定を定義した設定ファイル(log4net.config)を用意します。
さらにlog4net本体にlog4net.configの場所を教えてあげるため、AssemblyInfo.csファイルに以下の呪文を記載する必要があります。

呪文↓

[assembly: log4net.Config.XmlConfigurator(Watch = true,ConfigFile =@".\config\log4net.config")]

この呪文を唱えることで、log4netの起動時(LogManagerでGetLoggerメソッドを呼び出したとき)に、configFileで指定されたパスに存在するlog4net.configファイルを見つけられるようになります。

さて、この呪文、なぜWatch=trueのように定義しているのでしょうか。
確かに、このXmlConfiguratorクラスはWatchと、ConfigFileという名前のプロパティを持っています。
しかし、コンストラクタに、それら2つの値を受け付けるものは定義されていませんでした。
では、なぜ、上記のようにコンストラクタ風のメソッドを呼ぶときに同時にプロパティに値を設定できるのでしょうか・・・

と迷っていたら下のブログに行き着きました。
属性 | C# プログラミング解説

[ 属性クラス( 位置パラメータ, 名前付きパラメータ = 値 ) ]

ここでいう位置パラメータがコンストラクタの引数で、
名前付きパラメータはプロパティ及びフィールドとのことでした。

ということで、Watch=trueとかの記述方法についての謎が解けました!


なお、普通のクラスファイルの実装などで記述できる名前付きパラメータは以下のようになっています。
・代入したい変数名:代入したい値
Sampleコードは以下の通りです。

 //エントリポイント
 static void Main(string[] args)
 {
     logger.Debug("Test");
      //引数をあえて逆順に定義
      Test(b:"",a:"");
}

 private static void Test(string a, string b)
 {

 }

まとめ

属性クラスの設定方法で利用できる「名前付きパラメータ」と、
普通の実装で利用できる「名前付きパラメータ」は、それぞれ代入記号が異なります。
普通の実装で=(等号)を使って名前付きパラメータを使おうとすると、代入処理として認識されますので注意します!

REST × SOAP × MSDNマガジンで調査!

MSDNマガジンをあさっていたら気になったので、まとめてみました。


WCFWindows Communication Foundation

  • さまざまな通信プロトコルを同一のプログラミングモデルで取り扱うための仕組みのこと
  • (主に?)SOAP、REST、POXをサポート

SOAP:Simple Object Access Protocl

REST :Representational State Transfer

  • HTTPの仕様作成に参加されていたRoy Thomas Fielding による博士論文で提唱された
  • REST のアーキテクチャ スタイルを使用するサービスを一般に RESTful サービスまたはエンドポイントと呼ぶ
  • HTTPをベースとしているので、URIとGET、POSTなどのメソッドを利用してリソースにアクセスする
  • 同様に、HTTP Content-Typeで指定するリソースの種類にも、XHTMLXMLJSONなどが利用でる

まとめ

前にCognitive Serviceを使ったときにもWEB APIというか、RESTというか・・・を使っていましたが、よくよく調べてみると、奥が深いものだということがわかりました。
いつか論文読*1みたいなw

Windows 10 × 画面キャプチャ × 録画設定

Windows 10になってから仮想デスクトップやらなんやらと、これまでフリーソフトでやってきたことがWindowsの基本機能として利用できるようになってきました。
これらの機能で十分満足なのですが、画面キャプチャ機能もWindows 10にデフォルトで付属されていることをご存知でしょうか!?

今回は、Windows 10に搭載されている画面キャプチャ機能の使い方と、各種設定をまとめておきたいと思います。


起動方法

Windowsボタン】 + 【G】 で、録画設定画面が起動します。
f:id:kinakomotitti:20171202211222p:plain

Windowsボタン】 + 【Alt】 + 【R】 で直接録画が始まります。(録画ボタンを押下したときと同じ操作)

設定方法

設定アプリを起動して、【ゲーム】設定の・・・
f:id:kinakomotitti:20171202211550p:plain

【ゲームDVR】で設定ができます。
f:id:kinakomotitti:20171202211658p:plain


設定項目は、以下のようになっています。
自分の環境、録画方法に合わせて調整してください。
基本的にデフォルトで問題ないとは思いますがw

  • キャプチャした動画、もしくは静止画の保存先
  • バックグラウンド録画のON/OFF

 個人的に分かりにくい機能だったのですが、公式曰く、
「録画しておけばよかったと思うような魅力的なことが起ったときに役立つ機能です。この機能をオンにすると (既定ではオフ)、そうした魅力的な瞬間が永遠に消えてしまう前に、ゲームプレイの最後の瞬間をキャプチャすることができます。」
 また、パフォーマンスとしては、
「バックグラウンド録画は、バックグラウンドでゲームを録画するために PC のリソースを消費します。このため、ゲームのパフォーマンスに影響が出る可能性があります。」
 とのことです。

  • 最大録画時間

 初期設定は2時間ですが、その他には、30分、1時間、4時間を設定可能です。

  • 録音設定

 マイクのON/OFF(実況動画をとるときONにしておけば、ゲームの音と自分の声をかぶせて録音することができそうですね)

  • 録画されたビデオの品質

 これ、だいじですね。
 録画したビデオファイルのファイルサイズに影響してきます。
 デフォルトの設定で録画したとき、45分くらいで2㎇くらいかかりました。

その他

実際に録画をやってみると、気軽に録画が実行できて便利でした。
ただ、自分の環境では、ディスプレイの解像度が2560×1440になっていたこともあり、
45分録画 で 3GBくらいの録画ファイルになってしまいました。

youtubeなどにアップロードすることも考えると、もう少し小さいサイズのファイルで管理したいので、今後はディスプレイの解像度を落として録画するようにしますw


まとめ

ゲームDVR(Windowsの画面キャプチャ機能)はBandicamなどのフリーソフトに負けないくらい簡単に利用することができる!
ファイルサイズが気になるときは、ディスプレイの解像度を確認!
プレゼンの録画とかにも使えるかも・・・?使えないかも・・・?



support.xbox.com

Build × プラットフォームターゲット × 選択

最近こんな質問を受けてまともに答えられなかったので、調べた結果を備忘録として残しておきます。

質問はこんな感じでした。
Q :アプリケーションのプラットフォームターゲットを何にしたらよいか?

・・・Any CPUでいいじゃん。と思いましたが、
実行環境が64ビット端末だから、x64のほうが最適化されるのではないか。
という意見に対して、反応ができませんでした。


f:id:kinakomotitti:20171130224605p:plain
図:例の設定画面


ちゃんと見たことがなかったですが、初期設定では、【32ビット優先のAny CPU】となっています。
これは、32ビットの環境では32ビットアプリとして動き、64ビットの環境ではWoW64という64ビット版のWindowsで32ビットアプリケーションを動かすための技術を使って動きます。
32ビットの優先をなくしたときでも、Any CPUとしたら、32ビット環境では32ビットとして動作し、64ビット環境では64ビットアプリとして動作します。

逆にx86, x64などに設定したらどうなるかというと、
x86のときは、【32ビット優先のAny CPU】と同じような結果になります。
x64のときは、64ビット環境でのみ動作するモジュールが生成されます。

Windowsでは、実行可能ファイル(EXE)を実行するとき、EXEファイルのヘッダー情報をみて、アプリが32ビット or 64ビットのどちらのアドレス空間を必要としているかを判定します。
上記の設定は、このEXEを実行するときに必要となる情報を設定するものです。


よって、x86だと最適化されるという機能を勝手に妄想実装するのは間違いで、デフォルトの設定のまま【32ビット優先のAny CPU】としてビルドすればよいということがわかりました!
明日伝えておこう・・・


なお、特定のCPUのアーキテクチャに依存するような実装が必要な場合は、それぞれの環境にあったプラットフォームターゲットを選択する必要があるようです。

.NET Framework × CLR × 基礎知識

インストールされているCLRのバージョンを知りたい、調べたいことってよくありますよねw

そんな時、clrver.exeを使うことで、簡単に調べることができます!

 

・・・と、いうことが以下のブログで紹介されていました。

 

Did you know – You can check all the installed Common Language Runtime (CLR) Versions in your machine?

 

便利だなーと思ったところで、CLRってなんだっけってなったので、調べてみました。

 

まず、CLRとは、Common Language Runtimeという名前で、C#VBなど、いろいろなプログラミング言語から利用される共通部品のようなものです。

主要な機能としては、メモリ管理やスレッドの同期などがありますが、C#などのプログラミング言語を利用する実際の開発者は、CLRを意識しなくてもそれらの機能を利用することができます。

 

では、そんなCLRプログラミング言語との関係はどうなっているのでしょうか。

調べた結果、以下のような形で落ち着きました。

 

.NET Framework  ← Windowsに必須のフレームワーク

   ・アセンブリで構成されています。(mscoreei.dllなどがそれです。)

    ※アセンブリ(assembly) = コンポーネント とは?
     以下のものの 論理的な 集合体。
     フォルダみたいなもの。

      -モジュール(module) ← これ大事

                      -リソースファイル

 

     ・モジュールの種類

               ・managed module ← CLRによって管理されている=マネージド

      CLRを利用

      C#VBC++などで実装

               ・unmanaged module ← CLRによって管理されていない=アンマネージド

      CLRを使わずに、独自でメモリ管理などの機能を実装

      C++で実装

 

 

ということで、まとめです。

CLRはマネージドな言語が利用する共通部品のようなもの。

・それのバージョンを確認するためのツールがclrver.exe*1

*1:%systemroot%\Microsoft.NET\Frameworkのフォルダにあります。