- PR -

アプリケーションの操作ログ出力の実装方法

投稿者投稿内容
かつひと
常連さん
会議室デビュー日: 2006/06/01
投稿数: 32
投稿日時: 2009-01-31 11:26
 いつも勉強させて頂いております。
アプリケーションの操作ログ出力の実装方法についてご意見頂けないでしょうか。

 例えば、自作アプリで以下のようなログを出力するとします。
・ユーザーの操作履歴
  HH:mm:ss ○○ユーザー ログインしました。
  HH:mm:ss ○○ユーザー △△情報を検索しました。 etc
  ・・・
  ・・・

 アプリケーションが、UI・ドメイン・データアクセス層といったx層となっていた場合、UI層に実装するのが良いのでしょうか。
UI層でしか、ユーザーがどのような操作をしたか、そもそも判断できないと思いますが、

・開発者によって仕様の理解にばらつきがあると、ログ出力を実装したりしなかっりする。
  (実装以前の問題だと言われればそれまでですが...)
・以下のようなハードコーティング的なコードが散在する。
  例) Log.Write(userName + "△△情報を検索しました。");

という課題を感じています。
ぜひとも、ご教示頂けないでしょうか。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2009-01-31 12:13
引用:

かつひとさんの書き込み (2009-01-31 11:26) より:
 アプリケーションが、UI・ドメイン・データアクセス層といったx層となっていた場合、UI層に実装するのが良いのでしょうか。
UI層でしか、ユーザーがどのような操作をしたか、そもそも判断できないと思いますが、


まず、この「操作ログ」はデバッグ用なのでしょうか?それともデバッグとは無関係に必要なものなのでしょうか?
とりあえずおそらく後者だと仮定して書きます。

まず、アプリケーションを多層に分解して構築する場合は、「操作」というものはUI層だけではなく、それより下の層にも伝わるように作ったほうが良いです。

引用:

かつひとさんの書き込み (2009-01-31 11:26) より:
 例えば、自作アプリで以下のようなログを出力するとします。
・ユーザーの操作履歴
  HH:mm:ss ○○ユーザー ログインしました。
  HH:mm:ss ○○ユーザー △△情報を検索しました。 etc
  ・・・
  ・・・


で言うと、「ログイン」や「△△情報を検索」という「操作」は、UI層にもありますが、その下の層(おっしゃる層の名前で言うと「ドメイン」など)にも持っているようにアプリケーションを構築するものです。したがって、まず、アプリケーションの作りは「操作」が「ドメイン」層でも把握できるようにして、その層で操作ログを出力したほうが良いでしょう。

[ メッセージ編集済み 編集者: unibon 編集日時 2009-01-31 12:14 ]
かつひと
常連さん
会議室デビュー日: 2006/06/01
投稿数: 32
投稿日時: 2009-02-02 08:09
 ご教示頂き、ありがとうございます。

 UI層から下位へ操作を伝える実現方法について、想像がつかないのですが、もし差し支えございませんでしたら、実装の考え方や簡単なサンプルなど、お示し頂けないでしょうか。
自分なりの方法を検討したいと思っております。
King
ぬし
会議室デビュー日: 2008/06/20
投稿数: 284
投稿日時: 2009-02-02 09:31
全く見当違いだったら申し訳無いのですが、
操作IDやらメッセージIDやらを
引数やらプロパティやらで渡すのは駄目ですか?
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2009-02-02 12:49
引用:

かつひとさんの書き込み (2009-02-02 08:09) より:
 UI層から下位へ操作を伝える実現方法について、想像がつかないのですが、もし差し支えございませんでしたら、実装の考え方や簡単なサンプルなど、お示し頂けないでしょうか。


前回私が書いた中での「操作」とは広い意味での「オペレーション」という意味です。オブジェクト指向でいう「メッセージ」になります。マウスによるボタンを押すことや、キーボードによりテキストボックスに文字を入力すること、ということではないです。

例として、
http://www.atmarkit.co.jp/im/carc/serial/extend08/extend08c.html
から、図だけ借りて説明しますと、この図の中には「サービス層」「ドメイン層」「パーシステンス層」という分割になっており、ドメイン層の中に「会員チェック」メソッドと「貸出」メソッドがあります。
おっしゃる「操作ログ」には、これらのメソッドの呼び出しの記録をたんたんと書くようにすれば良いのではないか、と私は思います。「会員チェック」メソッドを呼んだこととその戻り値を見れば、「○○ユーザー ログインしました。」という行を「操作ログ」に書けます。また、「貸出」メソッドを呼びその戻り値を見れば、「○○ユーザー △△商品を借りました。」という行を「操作ログ」に書けます。

このように層を分割して作っておけば良いのではないでしょうか、ということです。
かつひと
常連さん
会議室デビュー日: 2006/06/01
投稿数: 32
投稿日時: 2009-02-02 17:32
 大変参考になるご意見、ありがとうございます。

 先に申し上げておくべきだったと思い反省しておりますが、ログを取る目的が不正操作の記録など、いわゆるセキュリティ上の理由によるところが大きいです。
ですので、操作( = クラスメソッドでも良いと思います)に加えて、誰が操作したか(ユーザー名)が必須の記録になると考えています。

 頂いたアドバイスを元に、自分なりに一例を考えてみたのですが、いかがでしょうか。

//ログ出力クラス
public class Log
{
 public static Write(DateTime dateTime, string userName, string log,・・・)
 {
  ・・・
 }
}

//アプリ情報を管理するクラス
public class AppInfo
{
 //ログインしているユーザー名を取得
 public static GetLoginUserName()
 {
  ・・・
 }
}

//ドメインクラス
public class Book
{
 public Book Get(string id)
 {
  Book book = new Book();
  ・・・
  Log.Write(DateTime.Now, AppInfo.GetLoginUserName, "Book.Get"・・・);
  return book;
 }
}

 ドメイン層(汎用)にアプリケーション固有メソッド呼び出しが入ってしまう点が気になるのですが、そこまで気にする必要はないのでしょうか。
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2009-02-02 17:55
ドメインレベルのログではなくアプリケーションレベルのログなので、
UI 層でやる、もしくは UI 層とドメイン層の間にアプリケーション層を用意してそこでやるのが良いかと思います。


で、こっからは思いつきで言います。
アプリケーション層を用意するとして、1機能1クラスにし、
それらのクラスの基本抽象クラスでログ出力をうまく実装してやれば、
各クラスではログ出力をほとんど意識せずに済みます。

コード:
public abstract class BusinessBase
{
    public BusinessBase(string businessName)
    {
        this._businessName = businessName;
    }
    private readonly string _businessName;
    public void Execute()
    {
        // 処理の開始を記録 (_businessName フィールドを使える)

        this.ExecuteImpl();

        // 処理の終了を記録 (_businessName フィールドを使える)
    }

    public abstract void ExecuteImpl();
}

public sealed class HogeBusiness : BusinessBase
{
    public HogeBusiness()
        : base("ほげ")
    {
    }

    public override ExecuteImpl()
    {
        // TODO : Implements (ログは意識しないで良い)
    }
}



_________________
C#と諸々
campylo
会議室デビュー日: 2008/12/15
投稿数: 5
投稿日時: 2009-02-02 18:11
引用:

 public static Write(DateTime dateTime, string userName, string log,・・・)


DateTimeはLog出力を行うメソッドで取得することにすれば、Log.Write()
をシンプルにできますね。
DateTimeにほんのわずかな遅れはありますが1秒に満たない差でしょう。

また、もしも、クライアントPC上で使うEXEでしたらユーザが切り替わ
ることはないと思われますので、毎回ユーザ名を渡さなくてもよいの
ではないかと思います。


引用:

 ドメイン層(汎用)にアプリケーション固有メソッド呼び出しが入ってしまう点が気になるのですが、そこまで気にする必要はないのでしょうか。



.NETに初めからあるSystem.Diagnostics.Traceで書くのも検討
してはいかがでしょうか。
.NET Framework クラス ライブラリ Trace クラス
http://msdn.microsoft.com/ja-jp/library/system.diagnostics.trace(VS.80).aspx

これにしておけば、TraceListenerを書き換えることでログ出力
を行いたいアプリケーションのコードを変更せずにログ出力の
挙動をあとから変更することができます。

_________________
campylo

スキルアップ/キャリアアップ(JOB@IT)