- PR -

Webアプリの操作履歴をログファイルに残したい

投稿者投稿内容
kanai
ベテラン
会議室デビュー日: 2004/09/13
投稿数: 98
投稿日時: 2005-08-02 13:07
あくまでひとつのアイディアに過ぎませんが、ButtonのClick、DropDownListのSelectedIndexChangedなど、ログを出力させたいコントロール、イベントが特定できるのであれば、それらのコントロールを継承し、ログを出力する機能を追加したものを使用する、というのはいかがでしょうか?

すでにWebアプリケーションが作成済みの場合、コントロールを差し替えるのが面倒ですが、新規に開発するならば、こういう方法もありかな、と思います。

コード:
Public Class LogButton
    Inherits System.Web.UI.WebControls.Button

    Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
        MyLog.PutLog(Me.Page.GetType.ToString, Me.ID & ".OnClick")
    End Sub

End Class


trapemiya
大ベテラン
会議室デビュー日: 2005/07/30
投稿数: 102
投稿日時: 2005-08-02 13:31
引用:

ちなみに、ボタンのクリックとか、AutoPostBack=Trueのアイテムとか、あくまで「ポストバックのきっかけになった操作のみを記録したい」という場合は、判別方法ってあるんでしょうか?あったとして、採用になるかは別問題ですけれども。。。


こちらが参考になると思います。

Page_LoadでPostBackの元になったボタン等の識別
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2005-08-02 15:12
引用:

kanaiさんの書き込み (2005-08-02 13:07) より:
あくまでひとつのアイディアに過ぎませんが、ButtonのClick、DropDownListのSelectedIndexChangedなど、ログを出力させたいコントロール、イベントが特定できるのであれば、それらのコントロールを継承し、ログを出力する機能を追加したものを使用する、というのはいかがでしょうか?
すでにWebアプリケーションが作成済みの場合、コントロールを差し替えるのが面倒ですが、新規に開発するならば、こういう方法もありかな、と思います。



おお!確かにそういう方法もありますね。
しかし、ご指摘の通り、画面は既にできてしまっているため、コントロールを差し替えるのが面倒すぎです(^^;

引用:

trapemiyaさんの書き込み (2005-08-02 13:31) より:
引用:

ちなみに、ボタンのクリックとか、AutoPostBack=Trueのアイテムとか、あくまで「ポストバックのきっかけになった操作のみを記録したい」という場合は、判別方法ってあるんでしょうか?あったとして、採用になるかは別問題ですけれども。。。


こちらが参考になると思います。

Page_LoadでPostBackの元になったボタン等の識別



おをを!これです!これを探してたんです!!
VB.NETに書き直すとこんな感じですかね。

コード:

Public Class BaseForm
    Inherits System.Web.UI.Page

    Private Sub Page_Load _
        (ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles MyBase.Load

        Dim id As String = ""
        If Len(Request("__EVENTTARGET")) > 0 Then
            id = Request("__EVENTTARGET")
        Else
            For Each ctl As String In Request.Form
                Dim c As Control = Page.FindControl(ctl)
                If TypeOf c Is System.Web.UI.WebControls.Button Then
                    id = c.ClientID
                    Exit For
                End If
            Next
        End If
        MyLog.PutLog(Me.GetType.ToString, id)
    End Sub
End Class

'ログ出力結果
2005/08/02,14:54:06.171,ASP.WebForm2_aspx,
2005/08/02,14:54:16.093,ASP.WebForm2_aspx,Button1
2005/08/02,14:54:17.281,ASP.WebForm2_aspx,Button2
2005/08/02,14:54:19.156,ASP.WebForm2_aspx,DropDownList1


あとは
・画面が巨大な場合ループ処理による性能への影響はないか?
・「ポストバックのきっかけになった操作」以外のイベントハンドラも記録しないといけないのか?
という2点と、実装に必要な工数とをはかりにかけて実装方法を決めたいと思います。

ご回答頂いた皆様、ありがとうございました。m(_ _)m
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-08-03 05:40
 すみません!投稿時間が限られている、ということで勘弁してください!!意図したことを正しく伝えられなかったようなので。
引用:

<実装方法その1>
各画面のクラスは全てのメソッド(イベントハンドラ)の冒頭に、ログ出力用のコードを書く。

<実装方法その2>
全ての画面はBaseFormクラスを継承しさえすれば、ログ出力に関しては何も意識しなくて良い。
ログ出力処理は全てBaseFormで行う(目的の形でログが出せればPage_Loadでなくても良い)


<実装方法その3>
各画面のクラスは、すべてのメソッドの冒頭に、ログ出力用のコードを書く。ただし、例えば [ PutLog(); ] のみ。
PutLog メソッド内で、StackTrace から呼び出し元メソッドを取得し、出力する。

つまり、この部分に注目。
> at sample.BaseForm.Page_PreRender(Object, EventArgs)
> at System.Web.UI.Control.OnPreRender(EventArgs)

 Page_PreRender は、このコードを書いた場所ですよね。で、次の OnPreRender は Page_PreRender の呼び出し元なわけです。
 ですから、PutLog メソッドで、StackTrace.GetFrame(1) は、現在実行中のメソッド(つまり PutLog)の呼び出し元(つまり、イベントハンドラ)になるのではないでしょうか?

 実装方法その2のように、一度書いたらあとは何もしなくて良い、ってことにはなりませんが、実装方法その1のように、コピーしたあとに書き換えが必要、というわけでもなくなります。
#実装方法その1で行くにしても、
#PutLog(System.Reflection.MethodBase.GetCurrentMethod().Name);
#だと、この行をコピーすればいいわけです。
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2005-08-03 12:14
引用:

Jittaさんの書き込み (2005-08-03 05:40) より:
 すみません!投稿時間が限られている、ということで勘弁してください!!意図したことを正しく伝えられなかったようなので。
−中略−
<実装方法その3>
各画面のクラスは、すべてのメソッドの冒頭に、ログ出力用のコードを書く。ただし、例えば [ PutLog(); ] のみ。
PutLog メソッド内で、StackTrace から呼び出し元メソッドを取得し、出力する。


ああっ、こちらこそすみません。
Jittaさんの意図が全く伝わってなかったわけではないんです。

ただ、最近継承の便利さがようやく理解できてきたとこで、可能ならば「一度書いたらあとは何もしなくて良い」という究極の横着(?)を使ってみたかった、というのがありまして(^^;
今回は、仕様上、ポストバックのきっかけになった操作だけ記録すればいい方向に落ち着きそうなので、実装方法その2を推してみたいと考えてます。

しかし、実装方法その3、これはこれで便利ですね。オーバーロードの見分けもつきますし
後々使うことになるかもしれないんで、PutLog改良版も作ってみました。

コード:

Public Shared Sub PutLog()
    Dim st As New StackTrace(False)
    Dim sf As StackFrame = st.GetFrame(1)
    Dim mb As MethodBase = sf.GetMethod()
    Dim className, methodName As String
    Dim dtNow As DateTime = Now()

    className = mb.DeclaringType.ToString()
    methodName = mb.Name & "("
    For i As Integer = 0 To mb.GetParameters.Length - 1
        Dim pi As ParameterInfo = mb.GetParameters(i)
        If i > 0 Then methodName &= ", "
        methodName &= pi.ParameterType.ToString()
        methodName &= " "
        methodName &= pi.Name
    Next
    methodName &= ")"

    SyncLock GetType(MyLog)
        Dim writer As New StreamWriter("C:\Temp\mylog2.txt", _
            True, Encoding.GetEncoding("Shift-JIS"))
        writer.WriteLine( _
            dtNow.ToString("yyyy/MM/dd") & vbTab & _
            dtNow.ToString("HH:mm:ss.fff") & vbTab & _
            className & vbTab & methodName)
        writer.Close()
    End SyncLock
End Sub

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