いまさら聞けない「log4net」の使い方

新人君も4ヶ月近く当社での経験を積んだので、成長の証にLog4netをプロジェクトへ導入する手順を書かせた。



ソリューションへNugetを使って、Packageをインストール

メニューの
 ツール > Nugetパッケージ マネージャー > ソリューションのNugetパッケージ管理

から、オンラインで「log4net」を検索して、該当プロジェクトへインストールする。

#設定ファイルをAssemblyInfo.csへ記述

該当プロジェクトの
 Properties > AssemblyInfo.csを開いて

//Log4Net設定ファイルを指定
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "./設定ファイル名.xml", Watch = true)]

プログラム開始時に、Log4netの設定ファイルの読込ませる

該当プロジェクトのProgram.csに

//アプリケーションのグローバル変数設定
string logFolderName = ログ書込用フォルダのPath;
Environment.SetEnvironmentVariable("グローバル変数名", logFolderName);

//Log4net設定ファイルを読込
//設定ファイルは、AssembleInfo.csへ記述済み
XmlConfigurator.Configure();

Log4netの設定ファイルを作成

AssemblyInfo.csに記述したPathへ、設定ファイルを作成する。

設定
 appender ログを出力するモジュール相当 用意されているタイプを設定
・コンソール
  ・ファイル
 など。

   appenderへ
    ・layout
・File名(Path含む)
    ・日付フォーマット
    ・ファイル切替
   などを設定

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>
    <!-- コンソール出力用 (VS 上 [出力] ウインドウへの出力) -->
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <!-- 出力文字列のフォーマット -->
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="@%-5level&gt;&gt; %message%newline" />
      </layout>
    </appender>

    <!-- 通常ログ:単一ファイル出力 -->
    <appender name="InfoLogDailyAppender" type="log4net.Appender.RollingFileAppender">
      <!-- ファイル名は日付ごと グローバル変数名で設定したフォルダのLogs¥Info_yyyyMMdd.logで出力-->
      <param name="File" value="${グローバル変数名}\Logs\Info_" />
      <param name="DatePattern" value='yyyyMMdd".log"' />
      <param name="RollingStyle" value="date" />
      <param name="StaticLogFileName" value="false" />

      <AppendToFile value="true" />

      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMax" value="Error" />
        <param name="LevelMin" value="Trace" />
      </filter>

      <layout type="log4net.Layout.PatternLayout">
        <ConversionPattern value="%date [%-5level] - %message%n" />
      </layout>
    </appender>

    <!-- エラーログ:分割ファイル出力 -->
    <appender name="ErrorLogDailyAppender" type="log4net.Appender.RollingFileAppender">
      <!-- ファイル名は日付ごと -->
      <param name="File" value="${グローバル変数名}\Logs\Error_" />
      <param name="DatePattern" value='yyyyMMdd".log"' />
      <param name="RollingStyle" value="date" />
      <param name="StaticLogFileName" value="false" />

      <param name="AppendToFile" value="true" />

      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMax" value="FATAL" />
        <param name="LevelMin" value="Warn" />
      </filter>

      <param name="MaximumFileSize" value="10MB" />
      <param name="MaxSizeRollBackups" value="10" />

      <layout type="log4net.Layout.PatternLayout">
        <ConversionPattern value="%date [%-5level] %class %method - %message%n" />
      </layout>
    </appender>

    <root>
      <!-- 使用する Appender -->
      <appender-ref ref="ConsoleAppender" />
      <appender-ref ref="InfoLogDailyAppender" />
      <appender-ref ref="ErrorLogDailyAppender" />
    </root>

  </log4net>
</configuration>

以上で設定は完了。

Logを出力

クラスに

//log4net
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);


ログ出力したいところで

 logger.Info("XXX完了");
 logger.Error("XXXX発生");


で、それぞれ、Info、Errorログが出力される。

ClickOnceで困った 2

本日、クライアントから電話があり
「XXXアプリのアップデートが失敗します。」
とのこと。

クライアントは数百台あるのだが、一発目のサポート依頼である。

ClickOnceで配布しているアプリを、昨日修正したので
本日起動すると、最初にアップデートのダイアログが出る。

アップデートをダウンロード中にエラーで止まると言う症状である。


ClickOnceで困った・・・sumurai993.hatenablog.com

のように、アンインストール、再インストールしても
エラーが出るらしい。


Google先生にお願いすると、

ClickOnceでインストールしたアプリにはWindowsレジストリ
アンインストール情報があるとのこと。

HKEY_CURRENT_USER
-Software\
-Microsoft
-Windows
-CurrentVersion
-Uninstall

ここにあるキーを調べて、ShortcutFileNameがアプリ名のものを削除


次に

インストールデータ

HKEY_CURRENT_USER
Software
Classes
Software
Microsoft
Windows
CurrentVersion
Deployment
SideBySide
2.0
PackageMetadata

の下にあるキーの下にあるキーでアプリ名が推測できるようなキーを削除


以上で再インストールが出来ました。

ClickOnceで、またも半日ツブす。

「はじめてのことだから、
    上手くいかなくても、いいんだよ。」


と、新入社員と自分に言い聞かせながら・・・・


1. ClickOnceのURLは、ケースセンシティブ?

 新人君へのOJTで、テスト用サーバーにClickOnceインストーラーを置くためのフォルダを作成してもらった。

 すぐに、
 「http://sample.example.com/Test1/
を作成しましたと、報告がきました。


 こちらは、インストールURLを
 「http://samaple.example.com/text1/

 と、していました。


 セットアップを発行して、FTPでアップロード。

 クリーンなマシンから、アクセスして[インストール]ボタンをクリック。

 何度やっても途中で、

URLDownloadToCacheFile failed with HRESULT '-2146697210'
Error: 'http://sample.example.com/Test1/Sample1.application' をダウンロードしようとしてエラーが発生しました。

 で、止まる。


 Google先生にお伺いして、見つけたものを次々と試すが進展なし。


 お昼食べて、ふっと思いついたのが

「ダウンロード失敗とは、パスが違う?????? ってこと?」

 と、言うことで、試しに、サーバー側フォルダを"test1"に書き換えると、
すんなりとインストールできました。


 やれやれ・・・・・


2. ClickOnceで配布するexeのコンパイルは気を付けよう。

 今回のアプリは、メインのexeの他に十本ちょいのクラスライブラリと、フォームを持ち、メインとは別スレッドで動作する必要のあるexeがあります。

 そして、これもClickOnceで配布するのですが、何度やっても

"デプロイメント内の参照が、アプリケーション マニフェスト内で定義された ID と一致しません"

と、エラーになる。


 又も、Google先生にお伺いして、見つけた中に回答がありました。

 ClickOnceでメインと一緒に配布するexeは、

  • プロジェクトのプロパティ

の部分で、マニフェストの欄を
  [マニフェストなしでアプリケーションを作成します]。

を選択します。


これで、メインを発行して問題無くインストールできました。



しかし、ClickOnceのエラーは、もう少し分かり易くはならないのい?

アプリケーションもWindowsとMacを出来る限り合わせる

Macにインストールしたアプリ

Windows版、Mac版があるもの

日本語IM
セキュリティソフト
  • ESET Cyber Security
ブラウザ

 メール環境は会社でGoogle Apps使用のためブラウザ上で使用する。

  • Firefow
クラウド(全デバイスでデータを同期させるため)
  • Pocket
  • oneDrive
テキストエディタ
IDE
  • phpStorm
  • pyCharm
ツール
  • Wire Shark(パケットモニタ)
  • Source Tree(gitクライアント)
画像・動画編集
ローカル仮想環境

Mac版がないので、代替を探したもの

 出来る限り使い勝手が同じ(見栄えや操作)ようになるようにした。

Mac用しかないアプリ

 Mac用のみリリースされているアプリ

Xcode
 ご存じAppleが提供しているIDE

・homebrew
 Debian系のパッケージ管理ツールのaptと同じように使えるMac用パッケージ管理ツール

・Alfred2
 ランチャー(アプリを起動するためのもの)かと思っていたら、マシン内やEvernoteからWikipediaAmazonなど、何でも対象に検索してくれる優れもの。

 無料版を使ってみて、即有料版にアップグレードした。

・BetterTouchTool
 トラックパッドをメチャ便利にしてくれる優れもの

・Sequel Pro
 MySQLGUIクライアント

Microsoft Remote Desktop
リモートでWindowsデスクトップが操作できるアプリ。無ければVNCでも良かった。

・iTerm2
画面が2分割、4分割、タブで開くなど便利なターミナル。

Windows版しかないもの


以上で、ほぼ使い勝手を統一できて、開発については、Windowsとそれ以外でマシンの使い分けができるようになりました。

C# アプリケーションのスタート時にフォームを開かないでシステムトレイに入れる

やりたいこと

セキュリティソフトなどのように、起動したらフォームを開かないで、Windowsのシステムトレイにアイコンを表示する。

例)20秒毎に何かを行い、システムトレイにバルーンでお知らせする。

実装

  • ウィザードで、C#Windowsフォームプロジェクトを作成する。
  • Form1にtimerコントロールを貼る。
  • timerコントロールのIntervalを20000ミリ秒に設定
  • Form1のShowInTaskbarプロパティをFalseに設定
  • Program.csを開いて、以下のように変更する。

  [STAThread]
  static void Main()
  {
    //ここの2行は変更なし
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    //二重起動を防ぐ
    //Mutexクラスの作成
    //"MyName"の部分を適当な文字列に変える
    System.Threading.Mutex mutex =
       new System.Threading.Mutex(true, "MyName", out createdNew);
    if (createdNew == false)
    {
      //起動させない
      return;
    }

    using (NotifyIcon icon = new NotifyIcon())
    {
      icon.Icon =  System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);

      //フォームのインスタンスを作成する
      Form1 form1 = new Form1();
      //Form1のNotifyIconメンバーに、このNotifyIconのインスタンスを登録
      form1.NotifyIcon = icon;

      //システムトレイのアイコンの右クリックメニュー登録
      icon.ContextMenu = new ContextMenu(new MenuItem[] {
        new MenuItem("ウィンドウを開く", (s, e) => {form1.ShowForm();}),
        new MenuItem("終了", (s, e) => { Application.Exit(); }),
      });
      icon.Visible = true;

      Application.Run();
      icon.Visible = false;
    }
    //ミューテックスを解放する
    mutex.ReleaseMutex();
  }
 


Form1の実装

 
    internal NotifyIcon NotifyIcon { get; set; }


    private void timer1_Tick(object sender, EventArgs e)
    {
      //balloonTip表示
      NotifyIcon.BalloonTipIcon = ToolTipIcon.Info;
      NotifyIcon.BalloonTipTitle = "20秒経ちましたよ!";
      NotifyIcon.BalloonTipText = "お知らせの本文ですよ!";
      //3秒表示
      NotifyIcon.ShowBalloonTip(3000);
    }

    //アイコン右クリックの「ウィンドウを開く」で呼ばれるメソッド
    public void ShowForm()
    {
      // フォームの表示
      this.Visible = true;
      if (this.WindowState == FormWindowState.Minimized)
      {
        // 最小化をやめる
        this.WindowState = FormWindowState.Normal;
      }

      // Notifyアイコン非表示
      NotifyIcon.Visible = false;
      this.Activate();
    }
      
    //フォームのイベント(ボタンクリックなど)で再度システムトレイに格納
    private void ShowIconSystemTray()
    {
      //フォームを非表示に
      this.Visible = false;
      //最小化
      this.WindowState = FormWindowState.Minimized;
      //システムトレイのアイコン表示
      NotifyIcon.Visible = true;
    }

Yosemiteが出たのでMacも併用を始めたらWindows捨てる気になった

[2015/07/22 追記]

背景

 Django利用のサービスやWordPressのPluginなどのサーバー側の開発も管理するようになったが、

  • Windowsでは、サーバー側の開発環境を作成するのがメンドウ
  • 丁度良いタイミングでYosemiteがリリースされた

ため、長い間インテリア化していたMac miniを使うことにした。

実環境

実際の環境は、
f:id:kz1114inazuma:20141122084856p:plain

のように、狭い机の上に、配置している。

  • 27inchモニタを横置きでメインに

を、WindowsMac OS XKVMスイッチで切り替えて使っている。

  • 24inchの縦置きモニタは、HDMIの切替機で切替
  • マウスはWindows用、トラックパッドはMac

なので、縦型にWindowsの画面を出してマウスで操作しながら、メイン画面のMacをキーボードで操作と言うことも出来る。

Windowsマシン

 OS:Windows 8.1
 
 VS2013を使ってWindows Formを使ったアプリの開発に使う

Mac mini

 OS:Yosemiteクリーンインストール

 2年前にメモリ8Gに増設し、ハードディスクはSSDに換装済みで放置してあったマシン

 後述するアプリをインストールして、サーバーサイド側の開発に使う

キーボード操作の共通化(US配列のキーボードを使用)


 今まではWindowsがメインだったので、

  • 日本語:英数切替 → 左Alt + 左バッククォート
  • コピぺなど → CtrlキーとC,V,X,Zなどの組合せ

が、Mac OSでは、

  • 日本語:英数切替 → コマンド + スペース
  • コピぺなど → コマンドキーとC,V,X,Zなどの組合せ

となっている。

 現在使用中のUS配列のWindwos用キーボードだと、コマンドキーがWindowsキーとなる。
操作が違うため、いちいち作業が中断する。慣れれば良いのかもしれないが、今までのクセは抜けない。

解決策

 Mac側に以下のアプリをインストールして操作をWindowsに合わせた。それぞれの使い方は
こちらMac - seil と Karabiner で日本語入力をカスタマイズする - Qiita
にあります(感謝)。
 

Karabiner

f:id:kz1114inazuma:20141122093253p:plain

これでWindwsキーとCtrlキーを入替ることで、Windowsと同じCtrl + C,V,X,Zなどが実現出来た。

ただ、iTerm2などでコマンド実行を中断する場合には、仕方ないのでWindowsキー + Cで行う。

Seil

f:id:kz1114inazuma:20141122093817p:plain


これで、設定ファイルに[Alt + バッククォート]を追加して、日本語:英数切替が出来るようになった。

Mac VS Windows

 最近は、Macのシェアが伸びてきたせいか、FirefoxChromeなどをはじめとしてWindowsMacともに動作するアプリが沢山あります。

は、毎日使うので同じ操作で使えるのはメチャ便利です。もうOSの違いを意識しないでも良いのかと思うくらいです。

Macの方が優れていること

 使い始めて3週間くらいですが、現在はVS2013を使う以外は、ほぼMac状態です。

理由は

Macは画面がキレイ過ぎる

 特に同じモニタを切り替えて使っているので差が歴然としている。目の疲れ方が全然違う。正直Windowsに戻れない。

MacUnix系との親和性が高すぎ

 ベースがBSDなので当然かもしれませんが、homebrewがあるので、Unix系のコマンド、アプリ、言語は全てOKな上にiTerm2で画面分割が強力。

 開発環境を作成するために使う、Vagrant(VertualBox)が便利過ぎ(Windows8.1ではVertualBoxが動かなかった)。

トラックパッド離せない

 BetterTouchToolとの組合せは卑怯なくらい便利過ぎ。


 このままWindowsを使わなくても良くなるのなら、VSを使うプロジェクトから抜ける方法を考えなくてはならない。

Macでチョっと困っていること

 タイミング的にいつなのか特定出来ないのだが、レインボーくるくるが出て操作を受け付けなることが、1日に数回ある。

 休憩しろと言うことなのかも知れないが、正直急いでいるときに限って出るので困っている。



 メイン画面は横画像、サブ画面は縦長の画像をデスクトップ背景として使っているが、再起動すると、それぞれに指定している壁紙フォルダがズレる。

 メイン画面に縦長画像が一部拡大表示され、サブ画面に横画像が一部拡大表示されるので都度設定し直しとなる。



[2015/07/22 追記]

 アップデートで最近は、レインボーくるくる(正式名は未だに知らない)は出なくなった。


再起動すると、縦壁紙の指定フォルダが切り替わる件は、使用しているHDMI切替機と私の使用方法が原因でした。

Yosemiteをシャットダウンする際に、シャットダウン完了前にWindowsに切替えると
Macからみれば、縦モニタがいなくなったと判断するようです。

その時点で、Macからは横モニタだけとなり、壁紙設定も横モニタだけになる。

次回、マルチモニタで起動しても、壁紙設定は、横しか残っていない。


対策
 Macシャットダウン時は、完了まで両モニタを切り替えない。



Windows!さようなら。君との付き合いもこれまでかな?

  • MS-Dos 3.x(詳しいバージョンは覚えていない)〜MS-Dox 5.x

と、Windowsと人生過ごしてきたが、この年にしてMacに切替とは・・・・思ってもいませんでした。


以上、ただの独り言です。



 

Windowsサービスを作る

初めてWindowsサービスを作ることになった。

とりあえず資料を漁る。

MSDN
方法 : Windows サービスを作成する
方法 : Windows サービス アプリケーションをデバッグする
Windows サービス アプリケーションの開発

後は、やってみてハマれば書くことにする。