サイクリックログ – プログラミング – Home

通知
すべてクリア

[解決済] サイクリックログ

固定ページ 1 / 2

DA
 DA
(@DA)
ゲスト
結合: 21年前
投稿: 10
Topic starter  

教えて下さい。

以下でサイクリックログを作ろうとしています。
・ログ出力の度にopen/close
・100件のレコードを出力したら先頭に戻って上書きしていく

fopenを使ってaモードでopenすれば追記はできるのですが
100件出力したときにfseekで先頭に戻ろうとしてもうまくいきません。
色々と調べたところ、aモードではfseekが使えないことがわかりました。

また、wでは出力済みのログがオープンのたびに消されてしまい
最後のログしか残っていません。

何かいい手段はないかとサイクリックログの手法を探しましたが
手詰まりの状態です。

御助言宜しくお願いします。


引用未解決
トピックタグ
悠
 悠
(@悠)
ゲスト
結合: 17年前
投稿: 40
 

w+

では?


返信引用
DA
 DA
(@DA)
ゲスト
結合: 21年前
投稿: 10
Topic starter  

>悠さん

レスありがとうございます。
w+も試してみましたが、やはり最後のログが残るだけのようです。。。

http://www9.plala.or.jp/sgwr-t/c/sec17.html
こちらの書込みモード別の動作を参考にしているのですが、
wではやはりサイズを0にしてしまうのですよね。
かといって、aモードだとシークを動かすことができないし。。。

皆さんはどのようにサイクリックログをされているのでしょうか?


返信引用
DA
 DA
(@DA)
ゲスト
結合: 21年前
投稿: 10
Topic starter  

現状のコードは以下のような感じです。

ログを吐き出す際には、以下の関数を呼んで

LOG(){


返信引用
DA
 DA
(@DA)
ゲスト
結合: 21年前
投稿: 10
Topic starter  

すみません、途中で送信してしまいました。。。

LOG(){

  static int logcnt = 0;

//ログ内容処理は割愛//
  logcnt += 1;

  fp = fopen(logingtest.log, a);

  //レコードが10件目にきたら先頭から上書きしたい
  if( (logcnt % 10) == 0){
   fssek(fp, 0, SEEK_SET);
   logcnt = 0;
  }

  fwrite(・・・
  fclose(fp);
}


返信引用
ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

r+で


返信引用
DA
 DA
(@DA)
ゲスト
結合: 21年前
投稿: 10
Topic starter  

>ryoさん

ありがとうございます。
r+も試してはいたのですがやはりだめです。
最後のログしか出力されていない?
シークが間違ってる気がしますが、いま試行錯誤してます。

最初にopenして、ログ書きっぱなしならサイクリック(シークで)も
可能なのですがそれだと正常終了できたときしかログが残らないんですよね。

あとは、ログを書き込む度に
一旦ファイルを読み込んで、バッファ内で新規ログに結合させて書込み。
ぐらいしか思いつかないのですが、これだと負荷が高い気がします。


返信引用
subaru
 subaru
(@subaru)
ゲスト
結合: 19年前
投稿: 381
 

>r+も試してはいたのですがやはりだめです。
>最後のログしか出力されていない?
>シークが間違ってる気がしますが、いま試行錯誤してます。

r+で開いた直後にSEEK_ENDにシークで。


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
 

サイクリックという仕様を想像してみたのですが、参考になるかな。
解らない点、不足している点があれば再度聞いてください。

#include <stdio.h>
#include <stdlib.h>

void Log()
{
static int logcnt = 0;
FILE *fp;
int ret;

logcnt++;

if (logcnt > 10) {
fp = fopen(logingtest.log, r+);
ret = fseek(fp, 5 * (logcnt % 10 - 1), SEEK_SET);
} else {
fp = fopen(logingtest.log, a+);
}
fprintf(fp, %3d\n, logcnt);
fclose(fp);
}

int main()
{
int i;
for (i = 0; i < 50; i++) {
printf(i == %d\n, i);
Log();
if (i == 13) {
// 異常終了
exit(-1);
}
}

// quit
printf(End.\n);
getchar();
return 0;
}


返信引用
wood
 wood
(@wood)
ゲスト
結合: 23年前
投稿: 895
 

最近あまり触っていないものでうろ覚えの私が意見するのも
なんなんですが

>DA 2008/12/21(日) 14:52:11
>
>LOG(){
>
>  static int logcnt = 0;
           ↑
これって、関数に入る度に初期化されませんか?
外部で定義するか、引数にしたほうが良くないですか?

確実な書き込みのために fflush も考慮したほうがよくないでしょうか
途中異常終了しても書き込んでくれますよ

途中異常終了したときは、ストリームバッファに残っている
未物理書き込み情報は破棄されますからね
特に書き込み量(1行あたりが)小さい時は必ずちょん切れます


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
 

> これって、関数に入る度に初期化されませんか?
> 外部で定義するか、引数にしたほうが良くないですか?

されませんよ。
関数の中でしか使わず、何回その関数が呼ばれたかのみ数える変数ですので、
私もこのように書くことはあります。


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

> 確実な書き込みのために fflush も考慮したほうがよくないでしょうか

以下のことなら書き込み直後にfcloseしてますのでこの観点でも問題ないと思います。

> fprintf(fp, %3d\n, logcnt);
> fclose(fp);

fcloseは(ファイルを閉じるので当然といえばたぶん当然に)まずフラッシュします。
stream to be flushed and the associated file to be closed.(ISO/IEC9899)

> printf(End.\n);
> getchar();

こっちの話なら分からないこともありませんが、
改行はしてるのでラインバッファになってればおそらく掃けますね。


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

ちなみに、先の例だとexitでもフラッシュされます。

Next, all open streams with unwritten buffered data are flushed,
all open streams are closed,
and all files created by the tmpfile function are removed.

つまり、想定される異常系処理でexitしているのであれば、
途中で途切れていることはないので、特定にも困らないかと。

# ちなみに、本当に異常終了(abnormal program termination)するabortだと
# フラッシュするかは処理系定義なのでコンパイラの仕様次第、
# 落ちバグの類はundefined behaviorなので、そもそも保証なし。


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

# ぱらぱらと連投すみません。

text streamでこの種のfseekするとundefined behavior扱いされるので、
bをつけておくべきかと。

> fp = fopen(logingtest.log, r+);
> ret = fseek(fp, 5 * (logcnt % 10 - 1), SEEK_SET);

# こっちなら平気。
# > fssek(fp, 0, SEEK_SET);


返信引用
DA
 DA
(@DA)
ゲスト
結合: 21年前
投稿: 10
Topic starter  

皆様、御回答ありがとうございます。
いっきにレスが付いていたのでびっくりしました^^;

レスから気付きがあり、少し解決に近づいています。
具体的にlogをどうしたいかというと、10レコードでサイクリックとして

(ログ10件未満の時)※時間は適当
001 22 09:40:35.966 aaa failed
002 22 09:40:35.966 bbbb failed
・・・
010 22 09:40:35.966 cccccc complete

(10件を越えた時)
011 22 09:40:35.966 d complete
012 22 09:40:35.966 ee failed
ed ←(002 22 09:40:35.966 bbbb failedのごみが残ってもいい)
・・・
010 22 09:40:35.966 cccccc complete

ということで、

num = strlen(buf);
numwrited += num;

//サイクリック開始後は、
if(logcnt > 10){
if( (logcnt % 10) == 1 ){
numwrited = 0;
}
//読み書きモードでopen
fp = fopen(szFileNameBuf, r+b);
fseek(fp, numwrited, SEEK_SET);
}
//サイクリック開始まではただの追記でopen
else{
fp = fopen(szFileNameBuf, a+b);
}

//bufをnumBYTE、一括で書込み
fwrite(buf, num, 1, fp);
fclose(fp);

サイクリック開始したら、
シークを先頭から書き込んだ分だけ進めて(これが気づきませんでした)、
そこに出力する手法をとってみたところ、
サイクリックはOK、しかし改行がうまくいかないようになってしまいました。

se025 035 22 09:40:55.247 xxx failed
22036 22 09:40:55.278 xxx fa037 22 09:40:55.293 xxx complete

シークするバイト数と、これまでに書き込んだバイト数の関係が怪しい気がします。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました