using System;
using System.IO;
using System.Text;
namespace Aivfo.OperationLog
{
///
/// 本地文件写入:调试级日志(14§4)+ 运行兜底(Kafka 发不出、队列满)+ 组件自身错误。
/// 按天滚动;内部加锁串行写;全 try 兜底,绝不抛给业务。
///
internal sealed class LocalFileWriter
{
private readonly string _dir;
private readonly object _lock = new object();
public LocalFileWriter(string dir)
{
_dir = string.IsNullOrEmpty(dir) ? "oplog_local" : dir;
try { Directory.CreateDirectory(_dir); } catch { /* ignore */ }
}
/// 调试级一行(结构化文本,不进 Kafka)。
public void WriteDebug(OperationLogMessage m)
{
var line = $"{DateTimeOffset.FromUnixTimeMilliseconds(m.Time):yyyy-MM-dd HH:mm:ss.fff}\t" +
$"[DEBUG]\ttrace={m.TraceId}\tmodule={m.Module}\top={m.Operation}\t" +
$"house={m.HouseSn}\twell={m.WellSn}\tresult={m.Result}\t" +
$"in={Truncate(m.Input)}\tout={Truncate(m.Output)}\terr={m.Error}";
Write("debug", line);
}
/// 兜底:完整 JSON 落本地(Kafka 不可用 / 队列满丢弃前保留)。
public void WriteFallback(string json)
{
Write("fallback", json);
}
/// 组件自身错误(连不上 Kafka、序列化失败等)。
public void WriteSelfError(string msg)
{
Write("error", $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}\t{msg}");
}
private void Write(string kind, string line)
{
try
{
var path = Path.Combine(_dir, $"oplog-{kind}-{DateTime.Now:yyyyMMdd}.log");
lock (_lock)
{
File.AppendAllText(path, line + Environment.NewLine, Encoding.UTF8);
}
}
catch { /* 本地写失败也不能拖垮业务 */ }
}
private static string Truncate(string s, int max = 500)
{
if (string.IsNullOrEmpty(s)) return s;
return s.Length <= max ? s : s.Substring(0, max) + "...(" + s.Length + ")";
}
}
}