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

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

新規登録して質問してみよう
ただいま回答率
85.42%
C#

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

Visual Studio

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

.NET Framework

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

Q&A

解決済

4回答

11846閲覧

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

hawazu

総合スコア6

C#

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

Visual Studio

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

.NET Framework

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

0グッド

0クリップ

投稿2017/02/17 07:08

編集2017/02/17 07:31

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

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

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

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

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

例)
接続依頼A

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

接続依頼B

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

処理依頼A

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

処理依頼B

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

以下、主なソースコードです。(例外等割愛)

共通のログ生成クラス 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で他スレッドから上書されないようにしたいです。 以上となりますが、何かご指摘等ありましたら、よろしくお願い致します。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t_obara

2017/02/17 07:21

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

2017/02/17 07:23

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

2017/02/17 08:28

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

2017/02/17 08:35

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

回答4

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 13:38

hawazu

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hawazu

2017/02/17 13:39

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

0

c#

1newLogger = log4net.LogManager.GetLogger(ProcessName);

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

投稿2017/02/17 08:42

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hawazu

2017/02/17 08:48

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

0

こんにちは。

ログインスタンス保持して出力する部分

(クラス変数宣言)
private ILog gLog;

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

csharp

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

投稿2017/02/17 08:08

tamoto

総合スコア4158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hawazu

2017/02/17 08:20

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

2017/02/17 08:52

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

2017/02/17 09:07

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

0

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

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

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

投稿2017/02/17 07:42

t_obara

総合スコア5488

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hawazu

2017/02/17 07:58 編集

ご回答、ありがとうございます。 同時アクセスというのが何をさしているのかわかりかねるのですが、スレッド毎にスレッド別でログファイルを出力するには同期オブジェクトを用いる必要があるというご指摘でしょうか。 それ以外に手立てがないという意味合いでしょうか。
t_obara

2017/02/17 08:26

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

2017/02/17 08:37

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

2017/02/17 08:44

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

2017/02/17 09:18

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

2017/02/17 09:56

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

2017/02/17 13:35

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.42%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問