Witam.
Chciałbym stworzyć dokładny log programu. Mam w swoim programie sporo metod writeline. Chcę wszystkie przekierowac do pliku. Czy jest jakiś sposób aby automatycznie przy wywołaniu metody writeline to co ląduje na oknie konsoli znalazło się także w pliku ? Wizja umieszczania przy każdym writeline ( a jest ich sporo) funkcji odpowiedzialnej za zapis do pliku przeraża mnie lekko ;].
PdR
Najprościej (to nie jest dobry wzorzec, ale dla małego programu do zaakceptowania) zrobić statyczną metodę
public class Logger
{
public static void Log(string msg)
{
// Zapis do pliku
// Wyświetlenie w konsoli
// ... cokolwiek innego
}
}
i przerobić wszystkie wywołania WriteLine() na Logger.Log(). Raz będziesz to musiał zrobić (masz za swoje za duplikowanie kodu :-P), ale potem każda zmiana będzie się odbywała w tym jednym miejscu.
fs = new FileStream("c:\out.txt", FileMode.Create);
sw = new StreamWriter(fs);
Console.SetOut(sw);
radziłbym jednak zmienić implementacje na coś w rodzaju http://www.nlog-project.org/
i zastosować statyczną metodę jak wyżej
Ale decek_1984 chce pisać i na konsolę, i do pliku.
Możesz napisać własną implementację strumienia (dziedzicząc po klasie Stream). Przeładuj metody Write i WriteByte tak, aby dane lądowały zarówno w pliku jak i w konsoli.
Później utwórz sobie obiekt StreamWriter piszący do twojego strumienia i jego używaj do pisania logów. Wystarczy podmienić wszystkie "Console." na "NazwaStreamWritera.", lub tak jak przedmówca zasugerował podmienić "Console.SetOut(NazwaStreamWritera);" z tym że wtedy implementacja strumienia musi sobie wcześniej zapisać "Console.Out", zanim zostanie podmieniony i korzystać z tego zapisanego.
Ja od pół roku korzystam z tego kodu i nie narzekam, choć może przydałoby się trochę wydajność zwiększyć, napisałem to w 10 min, gdy potrzebowałem logów, więc na cud nie licz, ale na początek wystarczy:
public class LogConsole
{
public static void WriteLine(String s, bool b){
StringBuilder builder = new StringBuilder();
builder.Append(DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss"));
builder.Append((char)9);
builder.Append(s);
if(b) Console.WriteLine(s);
StreamWriter sw = new StreamWriter("logs/log.txt", true);
sw.WriteLine(builder.ToString());
sw.Close();
}
public static void WriteLine(String s){
WriteLine(s, true);
}
}
W pliku każda linijka zawiera dokładny czas wystąpienia logu oraz treść po znaku tabulacji, więc wszystko wygląda dosyć porządnie. Najlepiej przy każdym uruchomieniu programu zrób jeszcze:
LogConsole.WriteLine("----------------------------", false);
Dzięki temu będziesz miał ładnie oddzielone wszystkie uruchomienia programu.
Acha, prawie zapomniałem, w katalogu, gdzie masz plik .exe utwórz folder o nazwie "logs", bo inaczej ci będzie wywalać wyjątek DirectoryNotFound albo coś podobnego.
Nie wystarczy takie coś?
private void Loguj(string _napis)
{
//wyświetlenie na konsoli
Console.WriteLine(_napis);
//dopisanie do pliku
File.AppendAllText(@"C:\log.txt", _napis + "\r\n");
}
somekind napisał(a)
Nie wystarczy takie coś?
private void Loguj(string _napis)
{
//wyświetlenie na konsoli
Console.WriteLine(_napis);
//dopisanie do pliku
File.AppendAllText(@"C:\log.txt", _napis + "\r\n");
}
Niby wystarczy, ale moja metoda daje bardziej eleganckie i szczegółowe informacje (data+godzina). Każda informacja może się przydać, a przy okazji, o ile dobrze pamiętam, to Append wymaga, aby plik był już wcześniej utworzony.
Ile jeszcze osób odpowie nie na temat ?
decek_1984 napisał(a)
Czy jest jakiś sposób aby automatycznie przy wywołaniu metody writeline to co ląduje na oknie konsoli znalazło się także w pliku
hubert_nnn napisał(a)
o ile dobrze pamiętam, to Append wymaga, aby plik był już wcześniej utworzony.
Źle pamiętasz.
A dodanie daty, godziny i imienia kota to też nie problem.
@adf - biorąc pod uwagę poziom pytania można stwierdzić, że jego autor sam nie wie, czego chce, więc być może, któraś porada "nie na temat" będzie dla niego lepsza niż przeciążanie strumieni.
Właśnie, przeciążenie głównej klasy konsoli bardzo szybko zapełniłoby dysk i spowodowałoby, że przy każdym uruchomieniu programu plik logu zwiększałby się o jakieś 10mb albo nawet więcej. Ja używam mojej klasy LogConsole do umieszczania tylko niezbędnych przy ewentualnym debugowaniu informacji w pliku, a i tak generuje mi ok 200-300 linijek.
Plik Logu to nie śmietnik, gdzie można zapisywać wszystko co się da. Taką rolę pełni konsola, a w logu umieszczać się powinno tylko to, co ważne.
adf88 napisał(a)
Przeładuj metody Write i WriteByte tak, aby dane lądowały zarówno w pliku jak i w konsoli.
.
Co to znaczy przeładuj ?
Ja bym nie tworzył nowego strumienia tylko TextWriter. Nie trzeba przeładowywać aż tylu metod (w Stream prawie wszystko jest abstract).
static void Main()
{
MyTextWriter myTextWriter = new MyTextWriter(@"C:\test.txt");
myTextWriter.WriteLine("to jest treść testowa");
Console.ReadKey(false);
}
class MyTextWriter : TextWriter
{
public MyTextWriter(string fileLog)
{
FileLog = fileLog;
}
private string fileLog;
public string FileLog
{
get { return fileLog; }
set
{
fileLogStream = File.AppendText(value);
fileLog = value;
}
}
private StreamWriter fileLogStream;
public override System.Text.Encoding Encoding
{
get { return Encoding.Unicode; }
}
public override void Write(char value)
{
Console.Write(value);
fileLogStream.Write(value);
fileLogStream.Flush();
}
}
decek_1984 napisał(a)
Co to znaczy przeładuj ?
Przeładowanie (przeciążenie) metody to stworzenie nowej metody o tej samej nazwie i zwracanym typie ale z inną listą parametrów. Nie należy tego mylić z override (ani new), które można tłumaczyć jako przesłonięcie/przedefiniowanie (albo nawet implementacja przy klasie abstrakcyjnej) i które robi co innego.