info@yenlo.com
ned
Menu
WSO2 7 min

Het verkrijgen van Console Log Output in JSON Log Format

Ontdek deskundige inzichten over logverwerking en JSON-format in de nieuwste blog van Fahri Kutay Özüdoğru bij Yenlo. Leer hoe je je dataverwerkingspijplijn efficiënt kunt optimaliseren!

Fahri Kutay Özüdoğru
Fahri Kutay Özüdoğru
Integration Consultant
Het verkrijgen van Console Log Output in JSON Log Format

Logstash (onderdeel van de Elastic Stack) is een dataprocessingpijplijn die je in staat stelt om gegevens te verzamelen uit verschillende bronnen, deze dynamisch te transformeren en naar je gewenste bestemming te sturen. Het wordt meestal gebruikt als een datapijplijn voor Elasticsearch, een open-source analyse- en zoekmachine. Als je gegevens echter al in JSON-indeling staan, is er geen noodzaak om Logstash te gebruiken. Door het standaard Log4j-formaat van WSO2 om te zetten naar JSON Log Formaat, kun je Logstash volledig omzeilen. Je kunt eenvoudig logs naar Filebeat sturen, die ze vervolgens opslaat in Elasticsearch.

Log4J en Log4J2 zijn de facto standaard frameworks voor het loggen van applicatieberichten in Java. In wezen, wanneer je Java-applicaties ontwikkelt, voeg je verschillende statements toe die informatie loggen volgens het niveau dat je instelt. Log4j is ook het standaard toepassingslogmechanisme voor WSO2-containers. Hier is een geweldig artikel, geschreven door onze collega Rob Blaauboer, als je meer wilt lezen over LOG4J2 en WSO2-interactie.

Als je ELK-stack gebruikt om gegevens uit verschillende bronnen in verschillende indelingen te publiceren en ze te doorzoeken, analyseren en visualiseren, en niet de vrijheid hebt om Logstash te configureren om de logregels om te zetten in JSON-strings vanwege beperkingen van je project, of als je onnodige serializeer-/deserialiseerbewerkingen wilt vermijden die veel systeembronnen kunnen verbruiken, wil je Logstash misschien omzeilen en je loguitvoer converteren naar JSON Log Formaat in plaats daarvan.

Het creëren van een aangepaste JSON Log Mediator

Allereerst, als we eigenschappen willen verstrekken en deze als afzonderlijke sleutel/waardeparen willen weergeven, hebben we onze eigen Log Mediator nodig, aangezien de ingebouwde Mediator de eigenschappen op de volgende manier instelt:

private void setCustomProperties(StringBuffer sb, MessageContext synCtx) {
    if (properties != null && !properties.isEmpty()) {
        for (MediatorProperty property : properties) {
            if(property != null){
            sb.append(separator).append(property.getName()).append(" = ").append(property.getValue()
                    != null ? property.getValue() :
                    property.getEvaluatedExpression(synCtx));
            }
        }
    }
}

Bij het onderzoeken van de ingebouwde log-mediator van WSO2, zien we dat de eigenschappen die aan de mediator worden geleverd, worden gelogd in het volgende formaat:

Separator (default is ‘,’) propertyName = propertyValue

In plaats van StringBuilder, wat het moeilijker zou maken om JSON-objecten te bouwen, zullen we een HashMap gebruiken en de eigenschappen toewijzen aan deze map die we aan het maken zijn.

private Map getCustomLogMessage(MessageContext synCtx) {
    Map<String,String> map = new HashMap<>();
    setCustomProperties(map, synCtx);
    return map;
}

private void setCustomProperties(Map<String,String> map, MessageContext synCtx) {
    if (properties != null && !properties.isEmpty()) {
        for (MediatorProperty property : properties) {
            if(property != null){
                map.put(property.getName(), property.getValue() != null ? property.getValue() : property.getEvaluatedExpression(synCtx));
            }
        }
    }
}

Aangezien de openbare void auditLog(Object msg) -methode van de MediatorLog-klasse in de onderstaande code het bericht opmaakt door de getFormattedLog van LoggingUtils-klasse aan te roepen,

/**
 * Log a message at level INFO to all available/enabled logs.
 */
public void auditLog(Object msg) {
    String formattedMsg = LoggingUtils.getFormattedLog(synCtx, msg);
    defaultLog.info(formattedMsg);
    if (synCtx.getServiceLog() != null) {
        synCtx.getServiceLog().info(msg);
    }
    if (traceOn) {
        traceLog.info(formattedMsg);
    }
}

zullen we het bericht in ThreadContext plaatsen of de info-methode van de org.apache.log4j.Logger-klasse rechtstreeks aanroepen (of een ander niveau) methode), zonder de log op te maken.

switch (category) {
    case CATEGORY_INFO :
        //synLog.auditLog(getLogMessage(synCtx));
        ThreadContext.putAll(getLogMessage(synCtx));
        log.info(new ObjectMessage(getLogMessage(synCtx)));
        break;
    case CATEGORY_ERROR :
        //synLog.auditError(getLogMessage(synCtx));
        ThreadContext.putAll(getLogMessage(synCtx));
        log.error(new ObjectMessage(getLogMessage(synCtx)));
        break;
}

//Clear the map!
ThreadContext.clearMap();

synLog.traceOrDebug("End : Log mediator");

Als je het bericht in de threadcontext plaatst, zorg er dan voor dat je de map wist. Als je dit niet doet, kunnen oude eigenschappen van verschillende logacties verschijnen in nieuwe loggebeurtenissen. Dit komt door de aard van het MDC-mechanisme dat wordt gebruikt door de ThreadContext.

We zullen een OSGi-bundel maken met Factory- en Serializer-klassen, de aangepaste mediator QName is jsonLog voor dit geval, wat de aangepaste mediator naam is die we gaan gebruiken bij het aanroepen van deze mediator. We laten vervolgens het .jar-bestand vallen in de {EI_HOME}/dropins-map.

Integration solutions with WSO2
Brochure Integration Solutions met WSO2

Een leveranciersoverzicht

Nu downloaden

Log4j.properties-bestand configureren (Enterprise Integrator 6.x.x)

De tweede stap is om te configureren hoe je logs opgemaakt worden. Er zijn tal van layout-bibliotheken beschikbaar. Voor dit project hebben we JSONEventLayoutV1 gebruikt. Bouw de broncode en verplaats deze naar de {EI_HOME}/lib-map. Vervolgens kun je het log4j.properties-bestand configureren. Voorbeeld:

log4j.appender.CARBON_CONSOLE=org.wso2.carbon.utils.logging.appenders.CarbonConsoleAppender
log4j.appender.CARBON_CONSOLE.layout=net.logstash.log4j.JSONEventLayoutV1

Voorbeeldgebruik van aangepaste Log Mediator

Hieronder staat een voorbeeld van hoe je onze nieuwe aangepaste log mediator kunt gebruiken. Het gebruik zal vergelijkbaar zijn met de ingebouwde Log Mediator. We zullen enkele eigenschappen verstrekken zoals correlatie-id, bericht-id, naam van de sequentie, bron van het bericht, bestemming van het bericht, een korte beschrijving van de API en de payload zelf; gewoon om te testen of het JSON-object correct is gemaakt.

<jsonLog level="custom">
    <property expression="$func:correlationid" name="correlationid"/>
    <property expression="$func:message" name="messageid"/>
    <property expression="$func:sequence" name="sequence"/>
    <property expression="$func:source" name="source"/>
    <property expression="$func:destination" name="destination"/>
    <property expression="$func:description" name="description"/>
    <property expression="$ctx:current_body" name="payload"/>
</jsonLog>  

Deze configuraties resulteren in de volgende JSON-consolelog:

{
  "@timestamp": "2022-11-21T03:59:00.542Z",
  "ecs.version": "1.2.0",
  "log.level": "INFO",
  "message": "{sequence=Generic_FaultSeq_v1, payload=<jsonObject><key1>value1</key1><key2>value2</key2></jsonObject>, destination=null, messageid=null, description=Start fault processing, correlationid=null, source=null}",
  "process.thread.name": "PassThroughMessageProcessor-1",
  "log.logger": "nl.rijksweb.mediator.JsonLogMediator",
  "labels": {
    "Correlation-ID": "2b530f10-e410-4cc7-878a-5dd42793aac2",
    "bundle.id": "255",
    "bundle.name": "synapse-core",
    "bundle.version": "2.1.7.wso2v271",
    "correlationid": "1",
    "description": "Start fault processing",
    "destination": "some other system",
    "messageid": "1",
    "payload": "<jsonObject><key1>value1</key1><key2>value2</key2></jsonObject>",
    "sequence": "Generic_FaultSeq_v1",
    "source": "some system"
  }
}

Configureer het log4j2.properties-bestand

Net zoals we deden bij Enterprise Integrator, moeten we ook met Micro Integrator configureren hoe je logs worden opgemaakt.
Met de wijzigingen in de afhankelijkheden en het Carbon Kernel Logging Framework werkte het downloaden van een externe JSON-layout niet voor MI4.1.0.

In dit geval, in plaats van een externe optie, deed het upgraden van de pax logging-versie van wso2v4 naar wso2v5 het trucje, aangezien wso2v5 log4j-layout-template-json bevat en wso2v4 niet. Je kunt de jar-bestanden pax-logging-api-2.1.0-wso2v5 en pax-logging-log4j2-2.1.0-wso2v5 downloaden en ze verplaatsen naar de {EI_HOME}/dropins-map.

Voorbeeld van log4j2.properties-bestand:

appender.CARBON_CONSOLE.type = Console
appender.CARBON_CONSOLE.name = CARBON_CONSOLE
appender.CARBON_CONSOLE.layout = JsonTemplateLayout
appender.CARBON_CONSOLE.layout.eventTemplateUri = classpath:EcsLayout.json
appender.CARBON_CONSOLE.layout.locationInfoEnabled = true
appender.CARBON_CONSOLE.filter.threshold.type = ThreshholdFilter
appender.CARBON_CONSOLE.filter.threshold.level = DEBUG

Met deze configuraties zullen we de jsonLog-mediator aanroepen, die we zojuist hebben gemaakt, en deze oproep zal de volgende JSON-consolelog uitvoeren:

{
  "@timestamp": "2022-11-21T03:59:00.542Z",
  "ecs.version": "1.2.0",
  "log.level": "INFO",
  "message": "{sequence=Generic_FaultSeq_v1, payload=<jsonObject><key1>value1</key1><key2>value2</key2></jsonObject>, destination=null, messageid=null, description=Start fault processing, correlationid=null, source=null}",
  "process.thread.name": "PassThroughMessageProcessor-1",
  "log.logger": "nl.rijksweb.mediator.JsonLogMediator",
  "labels": {
    "Correlation-ID": "2b530f10-e410-4cc7-878a-5dd42793aac2",
    "bundle.id": "255",
    "bundle.name": "synapse-core",
    "bundle.version": "2.1.7.wso2v271",
    "correlationid": "null",
    "description": "Start fault processing",
    "destination": "null",
    "messageid": "null",
    "payload": "<jsonObject><key1>value1</key1><key2>value2</key2></jsonObject>",
    "sequence": "Generic_FaultSeq_v1",
    "source": "null"
  }
}

Conclusie

Loggen is uiterst belangrijk voor alle zakelijke softwaretoepassingen en WSO2 is daarop geen uitzondering. Het loggen van informatie vanaf het moment dat het systeem binnenkomt, via welke mediatieflow het gaat, tot hoe het het systeem verlaat, kan systeembeheerders en ontwikkelaars kritieke informatie verschaffen. Het gebruik van tools zoals ELK-stack bundelt al je logs vanuit meerdere bronnen in één centrale locatie; wat enorm helpt bij het oplossen van problemen. Maar de implementatie ervan kan gepaard gaan met zijn eigen uitdagingen. Met de aangepaste jsonLog-mediator kun je geldige JSON-objecten genereren als console- (of bestands-)uitvoer en Logstash omzeilen om onnodige serialisatie-/deserialisatie te vermijden, die veel systeembronnen kunnen verbruiken. Speciale dank aan Philip Akyempon en Steve Liem voor hun ondersteuning.

Ik hoop oprecht dat deze informatie je helpt bij je projecten. Als je vragen hebt, aarzel dan niet om contact met ons op te nemen.

ned
Sluiten