[C#] log z programu

0

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

0

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.

0

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

0

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.

0

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.

0

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");
}
0
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.

0

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

0
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.

0

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.

0
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 ?

0

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();
}

}

0
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.

1 użytkowników online, w tym zalogowanych: 0, gości: 1