Logging aus externem Modul

  • Themenstarter Themenstarter Gelöschtes Mitglied 68249
  • Beginndatum Beginndatum
G

Gelöschtes Mitglied 68249

Gast
Hallo zusammen,

ich habe ein kleines Problem. Ich habe ein Projekt in dem ich viele Hilfsmodule gemacht habe, um mir ständig wiederkehrenden Code zu ersparen. In den Modulen habe ich kein Logging eingebaut, um eine redundante Log4J zu vermeiden.
Bisher war es total fein, dass wenn in einem Modul ein Fehler gedroppt ist, diesen zu fangen und dann eine eigene Exception zurück zu liefern und dann im Aufrufer damit um zu gehen.

Jetzt habe ich aber einen Fehler, den ich so nicht behandeln möchte.

Ich habe eine Hilfsklasse, die sich um CSV Input und Output kümmert.
Darin ist eine Methode, die mir aus dem Pfad der CSV ein JSONArray mit deren Inhalt liefert.

Die Methoden darin sehen jetzt so aus:
Java:
    private static JSONArray processWithHeader(List<String> lines) throws JSONException {
        Map<Integer, String> headlineMap = getHeadLine(lines.get(0));
        lines.remove(0);
        JSONArray jsonArray = new JSONArray();

        for(String line : lines) {
            JSONObject jsonObject = processLine(line, headlineMap);
            if(jsonObject != null) {
                jsonArray.put(jsonObject);
            }
        }

        return jsonArray;
    }

    private static JSONObject processLine(String line, Map<Integer, String> headlineMap) throws JSONException {
        JSONObject jsonObject = new JSONObject();
        List<String> lineSplit = newSplitLine(line);

        for(int i = 0; i < lineSplit.size(); i++) {
            try {
                jsonObject.put(headlineMap.get(i), lineSplit.get(i));
            } catch(NullPointerException | IndexOutOfBoundsException e) {
                return null;
            }
        }

        return jsonObject;
    }
Neu ist der Try-Catch-Block in Zeile 21 - 25 weil es hier zu einem Fehler kam. Die Datei hat 7 Überschriften, aber in einer einzelnen Zeile kommt es aufgrund eines Fehlers im Datenlieferanten dazu, dass das Programm 8 Werte erkennt, kommt also damit zu einem Fehler und das ganze Programm bricht ab (schlechtes Errorhandling, bau ich auch noch um). Mit dem Try-Catch-Block geht es jetzt zwar weiter, aber ich wüsste ja gerne, dass es in einer Zeile zu einem Fehler gekommen ist, weil in dem konkreten Fall jetzt muss im Lieferanten etwas korrigiert werden. Das würde mir ja mit der aktuellen Umsetzung niemals auffallen.
Jetzt habe ich über die Möglichkeiten nachgedacht mir irgendwie ein Logging in der Hilfsklasse auf zu bauen. Im AppacheHttpClient ist das doch auch so, dass ich dem über die JARs sage, welchen Logger ich verwende und dann wird das darüber geleitet.
Nachteil dabei ist, dass ich zum einen nicht weiß, wie das geht.

Könnt ihr mir erklären, wie das bei solchen externen Klassen geregelt wird, oder mir eine Stelle im Internet verweisen, wo ich das nachlesen kann? Ich weiß nicht mal, nach was ich googlen soll.
 
Also generell ist es üblich, auch in den Dependencies zu loggen.

Die Problematik, dass man da dann ggf. mehrere Logging Frameworks hat, kann man dann z.B. mit SLF4J lösen. Das ist eine Logging Fascade, die zwei Dinge macht:
a) Es sammelt Logs von diversen Frameworks ein (Bridging legacy APIs)
b) es gibt die Logmeldungen dann an ein anderes Framework aus (So man nicht slf4j-simple oder slf4j-nop nutzt - aber Details finden sich dazu im Manual von SLF4J).

Der Apache httpclient nutzt commons-logging. Dieses unterstützt - ähnlich wie slf4j - unterschiedliche Ausgaben (log4j, slf4j, java.logging, ...)
Das ist also in dieser Beziehung ähnlich wie SLF4J bezüglich Punkt b) aber ich bin mir nicht sicher, ob es auch den Punkt a mit dem bridging bietet
 
Zu log4j kann ich nichts sagen, aber
Java:
Map<Integer, String> headlineMap = getHeadLine(lines.get(0));
lines.remove(0);
da hätte ich dann doch zwei Anmerkungen:
  1. Sehe ich das richtig, dass das eine Map von Integer auf String ist, in der der Integer ein Listenindex ist?
  2. Löschen aus einer übergebenen List
Das kann man sicher schöner machen. Wie sehen denn getHeadLine und newSplitLine aus?
 
Sehe ich das richtig, dass das eine Map von Integer auf String ist, in der der Integer ein Listenindex ist?
Ja genau, ich splitte quasi am Komma und dann ist in der Map
0 - Überschrift 1
1 - Überschrift 2
2 - Überschrift 3
...
Ich hatte das mal in eine List gepackt, aber da kann es sein, dass der Index sich ändert, also dass Überschrift 1 mal auf Index 2 ist, dann passt am Ende alles nicht mehr. Hab auch schon Frameworks ausprobiert, war aber nicht so generisch verwendbar.
Löschen aus einer übergebenen List
Hm, jetzt wo du es sagst, sollte ich die Liste vielleicht erst klonen, aber theoretisch brauche ich die Liste einzig und allein dafür.

Wie sehen denn getHeadLine und newSplitLine aus?
Java:
private static Map<Integer, String> getHeadLine(String line) {
    String[] firstLine = line.split(",");
    Map<Integer, String> headlineMap = new HashMap<>();

    for(int i = 0; i < firstLine.length; i++) {
        String value = firstLine[i];
        headlineMap.put(i, value.trim());
    }
    return headlineMap;
}

private static List<String> newSplitLine(String line) {
    boolean ende = false;
    List<String> values = new ArrayList<>();

    String lineTemp = line;

    while (!ende) {
        int hochkommaIndex = lineTemp.indexOf("\"");
        int kommaIndex = lineTemp.indexOf(",");

        if (kommaIndex < 0) {
            if (lineTemp.length() > 0) {
                values.add(lineTemp);
            }
            ende = true;
            continue;
        }
        if (kommaIndex < hochkommaIndex || hochkommaIndex < 0) {
            String value = lineTemp.substring(0, kommaIndex);
            if ((kommaIndex + 1) > lineTemp.length()) {
                ende = true;
            } else {
                lineTemp = lineTemp.substring(kommaIndex + 1);
            }
            values.add(value);
        } else if (kommaIndex > hochkommaIndex) {
            int endeHochkomma = lineTemp.indexOf("\"", 1);

            String value = lineTemp.substring(1, endeHochkomma);
            if ((endeHochkomma + 2) > lineTemp.length()) {
                ende = true;
            } else {
                lineTemp = lineTemp.substring(endeHochkomma + 2);
            }
            values.add(value);
        }
    }

    return values;
}

kann man dann z.B. mit SLF4J lösen
Genau sowas hab ich gemeint. In meiner Lagacy-Anwendung hab ich genau SLF4J und log4j-slf4j-impl im Einsatz, weil ich eben viele Abhängigkeiten habe, die das voraussetzen. Aber wie arbeite ich damit in meiner Sub-Klasse, oder ist das im SLF4J ordentlich erklärt?
 
Ich hatte das mal in eine List gepackt, aber da kann es sein, dass der Index sich ändert, also dass Überschrift 1 mal auf Index 2 ist, dann passt am Ende alles nicht mehr. Hab auch schon Frameworks ausprobiert, war aber nicht so generisch verwendbar.
Das kann nicht sein, weil die Schleife
Java:
    for(int i = 0; i < firstLine.length; i++) {
        String value = firstLine[i];
        headlineMap.put(i, value.trim());
    }
einfach hochzählt. Du sparst Dir mit der Map nur, dass ein get() auf einen nicht existierenden Index null liefert, statt z. B. eine ArrayIndexOutOfBoundsException zu werfen. Das lässt sich aber leicht im Vorfeld abfangen.

Hm, jetzt wo du es sagst, sollte ich die Liste vielleicht erst klonen, aber theoretisch brauche ich die Liste einzig und allein dafür.
Da die Methode private ist, sehe ich das Problem auch eher darin, dass Du das ggf. im Kopf haben musst, wenn Du mal irgendwo was änderst (ändern musst). Klonen brauchst Du aber nicht, das kann man z. B. mit einem Stream oder List#subList lösen, in etwa so:
Java:
int n = lines.size();
for (String line : lines.subList(1, n)) {
...
}
 

Zurück
Oben