質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.53%

  • C#

    8795questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    2284questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • .NET Framework

    530questions

    .NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

マルチスレッドによるログインスタンスの保持(log4net)

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,868

hawazu

score 2

標記の件について、他スレッドからログインスタンスが初期化されてしまい、1スレッド=1ログインスタンスの状態を保ちたいです。

以下、出来ている部分を記載しましたので、ご確認下さい。

クライアントから接続依頼がきたらログインスタンスを生成し、
ファイル名に年月日とポート番号を指定しています。

接続ができたら対象のポート番号より、別の接続を確立させて、
処理依頼を待機します。

マルチスレッドで起動する事を許容しておりますが、
ログ出力先だけマルチスレッド制御出来ずにいます。

例)
接続依頼A

Aポートログファイル生成(ログインスタンス生成)

接続依頼B

Bポートログファイル生成(ログインスタンス生成)

処理依頼A

Aポートログファイルへ処理内容出力:×
→これがBポートログファイルに出力されます。

処理依頼B

Bポートログファイルへ処理内容出力:○

以下、主なソースコードです。(例外等割愛)
```.NET(C#)
共通のログ生成クラス
public static ILog GetLogger(string ProcessName, string SubFolder = "")
{
ILog newLogger = null;
log4net.Config.XmlConfigurator.Configure(new FileInfo(LOGCONFIGPATH));
newLogger = log4net.LogManager.GetLogger(ProcessName);
log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)newLogger.Logger;
if (logger.Parent.Appenders.Count != 0)
{
log4net.Appender.RollingFileAppender appender;
appender = (log4net.Appender.RollingFileAppender)logger.Parent.Appenders[0];
appender.DatePattern = "'_'yyyyMMdd'.log'";
if (SubFolder.Length == 0)
{
appender.File = @"..\Log\" + ProcessName;
}
else
{
appender.File = @"..\Log\" + SubFolder + @"\" + ProcessName;
}
appender.ActivateOptions();
}
return newLogger;
}

LogConfig.xml(一部抜粋)
<appender name="RollingFileAppender" 
type="log4net.Appender.RollingFileAppender">
<param name="File" value="" />
<param name="AppendToFile" value="true" />
<param name="MaxSizeRollBackups" value="10" />
<param name="MaximumFileSize" value="10000KB" />
<param name="RollingStyle" value="date " />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="" />
<layout type="log4net.Layout.PatternLayout">
<param name="conversionPattern" value="%d{yy/MM/dd HH:mm:ss}|%-5p|%C[%4L]|%c[%5t]|%m%n" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RollingFileAppender" />
<appender-ref ref="ConsoleAppender" />
</root>

ログインスタンス保持して出力する部分
(クラス変数宣言)
private ILog gLog;

(接続依頼がきたらロガー取得)
gLog = GSSCommon.GetLogger(SERVICE_NM  + port, subDir);
gLog.Info("接続確認");  ※ここでは対象のログに出力されている

(処理依頼がきたら処理開始) ※ここで最後にGetLoggerしたログファイルに出力されてる
gLog.Info("処理開始");

※以下、その他補足です。
・スレッドIDを出力してもスレッドIDは異なっていたので、マルチスレッドとしての仕組みは問題なさそうです。
・処理依頼直後にGetLoggerを再度行えば、傍目から見ればスレッド別に出力されますが、
処理中に別スレッドがGetLoggerしたら出力内容がログファイル別にぐちゃぐちゃになってそうです。
・起動するスレッド数は50~100程を予定し、1プロセスで20~50程度のスレッド数で予定してます。
・クラス内のログインスタンスを一度のGetLoggerで他スレッドから上書されないようにしたいです。

以上となりますが、何かご指摘等ありましたら、よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • t_obara

    2017/02/17 16:21

    できたら良いこと、現状はこれしかできない、詳細(今回ご提示された内容)に分けて記載されると、質問を読んだ時に誤解なく把握しやすいと思います。 補足に書いてある「他のプロセスから上書きされないようにしたい」のが一番やりたいことでしょうか?

    キャンセル

  • hawazu

    2017/02/17 16:23

    はい、お察しの通りです。すみません。わかりにくくて。修正します。

    キャンセル

  • PineMatsu

    2017/02/17 17:28

    1つのプロセスで1つのロガーインスタンスにしたいのか、1つのスレッドで1つのロガーインスタンスにしたいのか、どちらなのでしょうか?

    キャンセル

  • hawazu

    2017/02/17 17:35

    後者です。私の文面に不備があり、申し訳ないです。1スレッド=1ロガーを目標としてます。※初めの依頼を受けた際にプロセスという文言は修正済です

    キャンセル

回答 4

check解決した方法

0

以下のように修正して解消致しました。

皆様、ご回答、ご指摘ありがとうございました。

public static ILog GetLogger( string ProcessName, string SubFolder = "" )
{
ILog newLogger = null;
newLogger = log4net.LogManager.GetLogger(ProcessName);
log4net.Appender.RollingFileAppender appender = new log4net.Appender.RollingFileAppender()
{
MaxSizeRollBackups = 10,
AppendToFile = true,
Encoding = System.Text.Encoding.UTF8,
MaximumFileSize = "1000KB",
RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Date,
StaticLogFileName = false,
DatePattern = "'_'yyyyMMdd'.log'",
Layout = ・・・
};
if (SubFolder.Length == 0)
{
appender.File = @"..\Log\" + ProcessName;
} else
{
appender.File = @"..\Log\" + SubFolder + @"\" + ProcessName;
}
log4net.Repository.Hierarchy.Logger logger = (log4net.Repository.Hierarchy.Logger)newLogger.Logger;
appender.ActivateOptions();
logger.AddAppender(appender);
logger.Level = log4net.Core.Level.All;
logger.Hierarchy.Configured = true;
return newLogger;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/17 22:39

    原因切り分け等をもう少し早くすればよかったなと反省しております。
    ありがとうございました。

    キャンセル

0

ログ出力先だけマルチスレッド制御出来ずにいます。

これはファイルのことと考えると、同時アクセスの際に、待たされるスレッドが出てきます。
通常は同期オブジェクトを利用して、出力が混在しないように工夫します。

かなりの数のスレッドからアクセスされるとのことですので、かなり待たされる可能性がありますので、書き込み時間をできるだけ少なくする工夫が必要になります。
遅延書き込みなどが一例ですが、リスクもあるので、システム全体のことを検討した上で対策を決定していただければと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/17 16:58 編集

    ご回答、ありがとうございます。

    同時アクセスというのが何をさしているのかわかりかねるのですが、スレッド毎にスレッド別でログファイルを出力するには同期オブジェクトを用いる必要があるというご指摘でしょうか。

    それ以外に手立てがないという意味合いでしょうか。

    キャンセル

  • 2017/02/17 17:26

    ログファイルもスレッドごとに分けて出力するのではないのですよね?
    ログファイルもスレッドごとに分けてと言うことであれば、ログ出力用のインスタンスをスレッド単位で保持するようにすれば良いのではないでしょうか。

    キャンセル

  • 2017/02/17 17:37

    >出力用のインスタンスをスレッド単位で保持するようにすれば良いのではないでしょうか。
    はい、それを目的に進めてますが、どうも上手くいってません。
    それを実現するために今のソースでの不備や指摘等ありましたら頂きたい所存です。

    キャンセル

  • 2017/02/17 17:44

    基本的に、スレッドで実行される処理は一連の機能を包含するものですので、クラスにまとめます。
    そのクラスメンバにログを処理するインスタンスを保持すれば良いです。
    現状のクラスがログ処理用インスタンスを保有していると思いますが、そのクラス設計がよくないのだと思います。

    キャンセル

  • 2017/02/17 18:18

    その観点で見直してみます。かなり手詰まり状態ですが、、、

    キャンセル

  • 2017/02/17 18:56

    http://gomocool.net/gomokulog/?p=762
    上記あたりを参考にされてはいかがでしょうか。
    単純にtaskの中で、全てを実行すれば良いのでしょうけれど、必要に応じてクラス化すれば良いのではないでしょうか。

    キャンセル

  • 2017/02/17 22:35

    参考情報、ありがとうございます。
    Taskでの確認やサンプルでの確認でも同一事象が確認とれ、log4net側の設定、呼び出し等が原因である事が確認とれました。
    自己解決という形でしたが、本当に色々ご指摘ありがとうございました。

    キャンセル

0

こんにちは。

ログインスタンス保持して出力する部分 
(クラス変数宣言) 
private ILog gLog;

という部分が気になります。
同じメソッドを複数のスレッドから呼び、そのたびにフィールドを書き換えているわけですよね?
ローカル変数にすれば解決するように見えますが、何か不都合がありますか?質問からは、何のためにフィールドに格納しているのかが読み取れませんでした。

(接続依頼がきたらロガー取得) 
var gLog = GSSCommon.GetLogger(SERVICE_NM  + port, subDir); 
gLog.Info("接続確認");  ※ここでは対象のログに出力されている

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/17 17:20

    ご回答、ありがとうございます。

    いえ、ローカル変数にしてもGetLoggerを最後に行ったスレッドが他のスレッドのログインスタンスを全て上書してしまいます。

    キャンセル

  • 2017/02/17 17:52

    うーん、ローカルにしても上書きされるというのは、インスタンスの状態が変更されているということになるため、考えづらいです……本当にローカル変数を使用してもダメですか?だったらlog4net側がおかしいということになるんですが。

    キャンセル

  • 2017/02/17 18:07

    ローカル変数は試したので、間違いなくダメなのですが、log4net側がおかしいとなると共通のログ生成クラス や設定ファイルがおかしいのでしょうか。
    ※何がおかしいのか全くわからず途方に暮れてます。。

    キャンセル

0

newLogger = log4net.LogManager.GetLogger(ProcessName); 

上書きされるのは、ProsessNameだけでロガーを生成しているからじゃないですか?
1つのプロセスに複数のスレッドがあって、各々のスレッドが個別に異なったロガーを生成したいのですよね?だったら、スレッドに固有のIDかなにかをこの関数に追加で渡すようにして、「プロセス名+ID」でロガーを生成すれば別のインスタンスになると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/17 17:48

    ご回答、ありがとうございます。

    引数のProcessNameにはサービス名とポート番号を与えているので、ユニークではあります。
    ※1ポート:1スレッドという形です。

    キャンセル

同じタグがついた質問を見る

  • C#

    8795questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    2284questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • .NET Framework

    530questions

    .NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。