Wertermittlung beim Compilevorgang



  • Hallo,

    ich verwende ein Makro zum Loggen

    #define LOG_INF(lvl, logEvent)         \
     {std::ostrstream ostrm;\
                ostrm << logEvent << std::ends;                                 \
    			Logger::Write(lvl,ostrm.str());}
    

    jetzt würde ich gern schon beim programmstart ausgeben welches der höchste verwendete lvl ist. Wie kann ich das realisieren ?


  • Mod

    Du verwendest ein zweites Makro, z.B. LOG_LEVEL und verwendest dieses in LOG_INF und der Ausgabe beim Start.



  • Das verstehe ich leider nicht. Könntest du ein Beispiel geben bitte ?


  • Administrator

    1. Wieso verwendest du ein Makro, statt eines Funktiontemplates?
    2. Kannst du deine Frage ein wenig genauer erläutern? Welche höchste Verwendung? Die in deinem Programm? Wie soll das gehen?

    int main()
    {
      int x = 0;
      std::cin >> x;
    
      if(x > 0)
      {
        LOG_INF(10, "bla");
      }
      else
      {
        LOG_INF(0, "blu");
      }
    
      return 0;
    }
    

    Was ist nun der höchste verwendete Level? 10? Was ist wenn der User eine negative Zahl eingibt? Und wozu willst du sowas überhaupt wissen, bzw. ist es wirklich das, was du wissen willst?

    Grüssli



  • ich habe jetzt folgendes:

    static int xx;
    #define CNT(c) \
    	if (c>xx) xx=c;
    

    diese Lösung findet das Maximum der bisher (bis zum Punkt der Ausgabe) verwendeten Loglevel.

    Ich möchte aber gern den insgesamt im Projekt maximalen Loglevel wissen wollen. Ist das möglich ?


  • Mod

    Entschuldige, ich hatte dich beim ersten Lesen falsch verstanden: Nein, das geht allgemein so nicht.



  • Dravere schrieb:

    1. Wieso verwendest du ein Makro, statt eines Funktiontemplates?
    2. Kannst du deine Frage ein wenig genauer erläutern? Welche höchste Verwendung? Die in deinem Programm? Wie soll das gehen?

    int main()
    {
      int x = 0;
      std::cin >> x;
    
      if(x > 0)
      {
        LOG_INF(10, "bla");
      }
      else
      {
        LOG_INF(0, "blu");
      }
    
      return 0;
    }
    

    Was ist nun der höchste verwendete Level? 10? Was ist wenn der User eine negative Zahl eingibt? Und wozu willst du sowas überhaupt wissen, bzw. ist es wirklich das, was du wissen willst?

    Grüssli

    der Höchste Level ist 10.
    Das will ich wissen damit der Benutzer, falls er einen niedrigeren als den höchsten Loglevel eingestellt hat und in seinem Logfile nicht alles sieht, die Möglichkeit hat zu erfahren welchen Loglevel er maximal einstellen muss um alles zu sehen. Diese Information möchte ich als erstes in die logdatei schreiben. Der Logger soll aber möglichst auch in anderen Klassen verwendet werden so dass ich den maximalen Level nicht vorgeben möchte.

    Der Logger loggt alles was unter einem eingestellten Logevel liegt.
    z.B. Level = 3
    Log(1,"test1");
    Log(2,"test2");
    Log(3,"test3");
    Log(4,"test4");

    Ausgabe:
    test1
    test2



  • EDIT:
    Sorry vergiss es. Das hier war schmarrn!

    #define LOG_INF(lvl, logEvent)         \
     {std::ostrstream ostrm;\
                ostrm << logEvent << std::ends;   \
                #define MAX_lvl MAX(MAX_lvl, lvl);                    \
                Logger::Write(lvl,ostrm.str());}
    

    Aber Makros werden inzwischen meist als böse betrachtet.
    MAX_lvl muss scope frei /global sein. Ebenfalls ein no-no.

    Aber bei loggern, asserts und unit tests macht man öfter mal ne ausnahme...


  • Administrator

    @krxlprnft,
    Das bringt ein alter Hut, er will es vor dem Programmstart wissen, also quasi zur Kompilierzeit herausfinden. Das ist so gut wie unmöglich.

    @MBreuer,
    Es ist so gut wie unmöglich und auch wenig sinnvoll. Setzte am besten selber ein paar Warnungstufen, mach daraus ein enum , mach aus dem Makro ein Funktionstemplate, füge ein assert ein. Also ca. so:

    enum LogLevel
    {
      LLVL_MESSAGE,
      LLVL_WARNING,
      LLVL_ERROR,
      LLVL_FATAL
    };
    
    template<typename ObjectT>
    void logInfo(LogLevel lvl, ObjectT const& obj)
    {
      assert(lvl <= LLVL_FATAL && lvl >= LLVL_MESSAGE);
    
      // ... restlicher Code ...
    }
    
    // Theoretisch könntest du sogar dies statisch zur Kompilezeit prüfen lassen:
    template<LogLevel LVL, typename ObjectT>
    void logInfo(ObjectT const& obj)
    {
      static_assert(LVL >= LLVL_MESSAGE && LVL <= LLVL_FATAL);
    
      // ... restlicher Code ...
    }
    
    // Verwendung dann:
    logInfo<LogLevel::LLVL_ERROR>("bliblablub");
    

    Natürlich müsstest du eine static_assert Implementation haben oder selber erstellen. Boost bietet bereits eine an.

    Grüssli


  • Mod

    Also wenn es unbedingt sein muss(Draveres Vorschlag ist VIEL besser), wirst du externe Programme bemühen müssen. Mit grep und awk ist das ein einzeiliges Shellscript. Das Problem ist halt, dass der Präprozessor

    1. Nicht rechnen kann
    2. Keine Variablen kennt
    3. Sich nichts über verschiedene Übersetzungseinheiten merken kann

    1 und 2 kann man mit viel Trickserei noch umgehen, aber spätestens Punkt 3 erzwingt eine externe Lösung.


Anmelden zum Antworten