Estás viendo una versión antigua de esta página. Ve a la versión actual.

Comparar con el actual Ver el historial de la página

« Anterior Versión 8 Siguiente »


Al ejecutarse las aplicaciones Vue sólo en el navegador, por defecto los logs que se obtienen no se quedan guardados, sólo se muestran en la consola del navegador. Para poder loggear también esta parte de las aplicaciones, hemos incluido un frontLogger, compuesto de un endpoint en el backend al que el frontend mandará los logs, de forma que podremos consultar en Lagar también los logs que vienen del frontend.

La configuración tanto del frontend como del backend ya estarán incluidas en los proyectos si hemos creado uno nuevo recientemente, y hemos seguido las instrucciones de la documentación. En el caso de proyectos más antiguos, creados antes de que hubiésemos sacado el log sí que habrá que seguir los pasos siguientes.

Configuración frontend

En nuestro proyecto Vue, en primer lugar tendremos que tener el archivo JSNLog.2-30-0.min.js en la ruta /public/js/ de nuestro proyecto (creamos la carpeta js). Podemos descargar el archivo clickando en el enlace anterior, o podemos crearlo nosotros mismos, con el mismo nombre, desplegar el siguiente bloque de código y copiar su contenido al archivo:

JSNLog.2-30-0.min.js
/* eslint-disable */
/*
 * JSNLog 2.30.0
 * Open source under the MIT License.
 * Copyright 2012-2017 Mattijs Perdeck All rights reserved.
 */
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(a,c,f){a!=Array.prototype&&a!=Object.prototype&&(a[c]=f.value)};$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);
$jscomp.polyfill=function(a,c,f,e){if(c){f=$jscomp.global;a=a.split(".");for(e=0;e<a.length-1;e++){var k=a[e];k in f||(f[k]={});f=f[k]}a=a[a.length-1];e=f[a];c=c(e);c!=e&&null!=c&&$jscomp.defineProperty(f,a,{configurable:!0,writable:!0,value:c})}};$jscomp.polyfill("Object.setPrototypeOf",function(a){return a?a:"object"!=typeof"".__proto__?null:function(a,f){a.__proto__=f;if(a.__proto__!==f)throw new TypeError(a+" is not extensible");return a}},"es6","es5");
var __extends=this&&this.__extends||function(){var a=function(c,f){a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,c){a.__proto__=c}||function(a,c){for(var f in c)Object.prototype.hasOwnProperty.call(c,f)&&(a[f]=c[f])};return a(c,f)};return function(c,f){function e(){this.constructor=c}a(c,f);c.prototype=null===f?Object.create(f):(e.prototype=f.prototype,new e)}}();
function JL(a){if(!a)return JL.__;Array.prototype.reduce||(Array.prototype.reduce=function(a,c){for(var f=c,e=0;e<this.length;e++)f=a(f,this[e],e,this);return f});var c="";return("."+a).split(".").reduce(function(a,e,k,n){c=c?c+("."+e):e;e=a["__"+c];void 0===e&&(JL.Logger.prototype=a,e=new JL.Logger(c),a["__"+c]=e);return e},JL.__)}
(function(a){function c(a,b,g){void 0!==b[a]&&(null===b[a]?delete g[a]:g[a]=b[a])}function f(d){if(null!=a.enabled&&!a.enabled)return!1;try{if(d.userAgentRegex&&!(new RegExp(d.userAgentRegex)).test(navigator.userAgent))return!1}catch(b){}try{if(d.ipRegex&&a.clientIP&&!(new RegExp(d.ipRegex)).test(a.clientIP))return!1}catch(b){}return!0}function e(a,b){try{if(a.disallow&&(new RegExp(a.disallow)).test(b))return!1}catch(g){}return!0}function k(a){return"function"==typeof a?a instanceof RegExp?a.toString():
a():a}function n(d){d=k(d);switch(typeof d){case "string":return new l(d,null,d);case "number":var b=d.toString();return new l(b,null,b);case "boolean":return b=d.toString(),new l(b,null,b);case "undefined":return new l("undefined",null,"undefined");case "object":if(d instanceof RegExp||d instanceof String||d instanceof Number||d instanceof Boolean)return b=d.toString(),new l(b,null,b);b="function"===typeof a.serialize?a.serialize.call(this,d):JSON.stringify(d);return new l("",d,b);default:return new l("unknown",
null,"unknown")}}function r(d,b,g){a.entryId++;return new t(d,b,g,a._getTime(),a.entryId)}function u(a){a.id&&(clearTimeout(a.id),a.id=null)}function v(a,b,g){var d=this;a.id||(a.id=setTimeout(function(){g.call(d)},b))}a.requestId="";a.entryId=0;a._createXMLHttpRequest=function(){return new XMLHttpRequest};a._getTime=function(){return(new Date).getTime()};a._console=console;a._appenderNames=[];var l=function(){return function(a,b,g){this.msg=a;this.meta=b;this.finalString=g}}();a.setOptions=function(a){c("enabled",
a,this);c("maxMessages",a,this);c("defaultAjaxUrl",a,this);c("clientIP",a,this);c("requestId",a,this);c("defaultBeforeSend",a,this);c("serialize",a,this);return this};a.getAllLevel=function(){return-2147483648};a.getTraceLevel=function(){return 1E3};a.getDebugLevel=function(){return 2E3};a.getInfoLevel=function(){return 3E3};a.getWarnLevel=function(){return 4E3};a.getErrorLevel=function(){return 5E3};a.getFatalLevel=function(){return 6E3};a.getOffLevel=function(){return 2147483647};var h=function(){return function(a,
b){this.inner=b;this.name="JL.Exception";this.message=n(a).finalString}}();a.Exception=h;h.prototype=Error();var t=function(){return function(a,b,g,c,f){this.l=a;this.m=b;this.n=g;this.t=c;this.u=f}}();a.LogItem=t;h=function(){function d(b,g){this.appenderName=b;this.sendLogItems=g;this.level=a.getTraceLevel();this.sendWithBufferLevel=2147483647;this.storeInBufferLevel=-2147483648;this.bufferSize=0;this.batchSize=1;this.maxBatchSize=20;this.batchTimeout=2147483647;this.sendTimeout=5E3;this.buffer=
[];this.batchBuffer=[];this.batchTimeoutTimer={id:null};this.sendTimeoutTimer={id:null};this.nbrLogItemsBeingSent=this.nbrLogItemsSkipped=0;if(void 0==b)throw"Trying to create an appender without a name or with an empty name";if(-1!=a._appenderNames.indexOf(b)){if(!b)throw"Trying to create an appender without a name or with an empty name";throw"Multiple appenders use the same name "+b;}a._appenderNames.push(b)}d.prototype.addLogItemsToBuffer=function(b){if(this.batchBuffer.length>=this.maxBatchSize)this.nbrLogItemsSkipped+=
b.length;else{if(null!=a.maxMessages){if(1>a.maxMessages)return;a.maxMessages-=b.length}this.batchBuffer=this.batchBuffer.concat(b);var g=this;v(this.batchTimeoutTimer,this.batchTimeout,function(){g.sendBatch.call(g)})}};d.prototype.batchBufferHasOverdueMessages=function(){for(var b=0;b<this.batchBuffer.length;b++)if(a._getTime()-this.batchBuffer[b].t>this.batchTimeout)return!0;return!1};d.prototype.batchBufferHasStrandedMessage=function(){return null!=a.maxMessages&&1>a.maxMessages&&0<this.batchBuffer.length};
d.prototype.sendBatchIfComplete=function(){(this.batchBuffer.length>=this.batchSize||this.batchBufferHasOverdueMessages()||this.batchBufferHasStrandedMessage())&&this.sendBatch()};d.prototype.onSendingEnded=function(){u(this.sendTimeoutTimer);this.nbrLogItemsBeingSent=0;this.sendBatchIfComplete()};d.prototype.setOptions=function(b){c("level",b,this);c("ipRegex",b,this);c("userAgentRegex",b,this);c("disallow",b,this);c("sendWithBufferLevel",b,this);c("storeInBufferLevel",b,this);c("bufferSize",b,this);
c("batchSize",b,this);c("maxBatchSize",b,this);c("batchTimeout",b,this);c("sendTimeout",b,this);this.bufferSize<this.buffer.length&&(this.buffer.length=this.bufferSize);if(this.maxBatchSize<this.batchSize)throw new a.Exception({message:"maxBatchSize cannot be smaller than batchSize",maxBatchSize:this.maxBatchSize,batchSize:this.batchSize});return this};d.prototype.log=function(a,g,c,d,m,w,h){!f(this)||!e(this,w)||m<this.storeInBufferLevel||(a=r(m,w,h),m<this.level?0<this.bufferSize&&(this.buffer.push(a),
this.buffer.length>this.bufferSize&&this.buffer.shift()):(this.addLogItemsToBuffer([a]),m>=this.sendWithBufferLevel&&this.buffer.length&&(this.addLogItemsToBuffer(this.buffer),this.buffer.length=0),this.sendBatchIfComplete()))};d.prototype.sendBatch=function(){if(!(0<this.nbrLogItemsBeingSent)&&(u(this.batchTimeoutTimer),0!=this.batchBuffer.length)){this.nbrLogItemsBeingSent=this.batchBuffer.length;var a=this;v(this.sendTimeoutTimer,this.sendTimeout,function(){a.onSendingEnded.call(a)});this.sendLogItems(this.batchBuffer,
function(){a.batchBuffer.splice(0,a.nbrLogItemsBeingSent);0<a.nbrLogItemsSkipped&&(a.batchBuffer.push(r(4E3,"Lost "+a.nbrLogItemsSkipped+" messages. Either connection with the server was down or logging was disabled via the enabled option. Reduce lost messages by increasing the ajaxAppender option maxBatchSize.",a.appenderName)),a.nbrLogItemsSkipped=0);a.onSendingEnded.call(a)})}};return d}();a.Appender=h;var p=function(d){function b(a){return d.call(this,a,b.prototype.sendLogItemsAjax)||this}__extends(b,
d);b.prototype.setOptions=function(a){c("url",a,this);c("beforeSend",a,this);d.prototype.setOptions.call(this,a);return this};b.prototype.sendLogItemsAjax=function(b,c){try{if(f(this)){this.xhr&&0!=this.xhr.readyState&&4!=this.xhr.readyState&&this.xhr.abort();this.xhr=a._createXMLHttpRequest();var d="/jsnlog.logger";null!=a.defaultAjaxUrl&&(d=a.defaultAjaxUrl);this.url&&(d=this.url);this.xhr.open("POST",d);this.xhr.setRequestHeader("Content-Type","application/json");this.xhr.setRequestHeader("JSNLog-RequestId",
a.requestId);var g=this;this.xhr.onreadystatechange=function(){4==g.xhr.readyState&&200<=g.xhr.status&&300>g.xhr.status&&c()};var e={r:a.requestId,lg:b};"function"===typeof this.beforeSend?this.beforeSend.call(this,this.xhr,e):"function"===typeof a.defaultBeforeSend&&a.defaultBeforeSend.call(this,this.xhr,e);var h=JSON.stringify(e);this.xhr.send(h)}}catch(y){}};return b}(h);a.AjaxAppender=p;var q=function(c){function b(a){return c.call(this,a,b.prototype.sendLogItemsConsole)||this}__extends(b,c);
b.prototype.clog=function(b){a._console.log(b)};b.prototype.cerror=function(b){a._console.error?a._console.error(b):this.clog(b)};b.prototype.cwarn=function(b){a._console.warn?a._console.warn(b):this.clog(b)};b.prototype.cinfo=function(b){a._console.info?a._console.info(b):this.clog(b)};b.prototype.cdebug=function(b){a._console.debug?a._console.debug(b):this.cinfo(b)};b.prototype.sendLogItemsConsole=function(b,c){try{if(!f(this)||!a._console)return;var d;for(d=0;d<b.length;++d){var g=b[d],e=g.n+": "+
g.m;"undefined"===typeof window&&(e=new Date(g.t)+" | "+e);g.l<=a.getDebugLevel()?this.cdebug(e):g.l<=a.getInfoLevel()?this.cinfo(e):g.l<=a.getWarnLevel()?this.cwarn(e):this.cerror(e)}}catch(x){}c()};return b}(h);a.ConsoleAppender=q;h=function(){function a(a){this.loggerName=a;this.seenRegexes=[]}a.prototype.setOptions=function(a){c("level",a,this);c("userAgentRegex",a,this);c("disallow",a,this);c("ipRegex",a,this);c("appenders",a,this);c("onceOnly",a,this);this.seenRegexes=[];return this};a.prototype.buildExceptionObject=
function(a){var b={};a.stack?b.stack=a.stack:b.e=a;a.message&&(b.message=a.message);a.name&&(b.name=a.name);a.data&&(b.data=a.data);a.inner&&(b.inner=this.buildExceptionObject(a.inner));return b};a.prototype.log=function(a,c,d){var b=0;if(!this.appenders)return this;if(a>=this.level&&f(this)&&(d?(b=this.buildExceptionObject(d),b.logData=k(c)):b=c,c=n(b),e(this,c.finalString))){if(this.onceOnly)for(b=this.onceOnly.length-1;0<=b;){if((new RegExp(this.onceOnly[b])).test(c.finalString)){if(this.seenRegexes[b])return this;
this.seenRegexes[b]=!0}b--}c.meta=c.meta||{};for(b=this.appenders.length-1;0<=b;)this.appenders[b].log(1E3>=a?"trace":2E3>=a?"debug":3E3>=a?"info":4E3>=a?"warn":5E3>=a?"error":"fatal",c.msg,c.meta,function(){},a,c.finalString,this.loggerName),b--}return this};a.prototype.trace=function(a){return this.log(1E3,a)};a.prototype.debug=function(a){return this.log(2E3,a)};a.prototype.info=function(a){return this.log(3E3,a)};a.prototype.warn=function(a){return this.log(4E3,a)};a.prototype.error=function(a){return this.log(5E3,
a)};a.prototype.fatal=function(a){return this.log(6E3,a)};a.prototype.fatalException=function(a,c){return this.log(6E3,a,c)};return a}();a.Logger=h;a.createAjaxAppender=function(a){return new p(a)};a.createConsoleAppender=function(a){return new q(a)};h="undefined"!==typeof window?new p(""):new q("");a.__=new a.Logger("");a.__.setOptions({level:a.getDebugLevel(),appenders:[h]})})(JL||(JL={}));"undefined"!==typeof exports&&(exports.__esModule=!0,exports.JL=JL);var define;
"function"==typeof define&&define.amd&&define("jsnlog",[],function(){return JL});"function"==typeof __jsnlog_configure&&__jsnlog_configure(JL);"undefined"===typeof window||window.onerror||(window.onerror=function(a,c,f,e,k){JL("onerrorLogger").fatalException({msg:"Uncaught Exception",errorMsg:a?a.message||a:"",url:c,"line number":f,column:e},k);return!1});
"undefined"===typeof window||window.onunhandledrejection||(window.onunhandledrejection=function(a){JL("onerrorLogger").fatalException({msg:"unhandledrejection",errorMsg:a.reason?a.reason.message:a.message||null},a.reason)});

Después, necesitamos la dependencia @mncs/fwjs-components en la versión 0.1.40 o superior. Podemos instalar la última versión con:

npm i --save @mncs/fwjs-components

O si ya lo tenemos, actualizando la versión en package.json (y haciendo un npm i para que se nos actualice en local).

Necesitaremos añadir estas dos variables de entorno al archivo .env:

VUE_APP_API_URL=/consultaexpedientes/rest/v1.0
VUE_APP_UMU_CLIENT_APP=consultaexpedientes-ui
  • VUE_APP_API_URL: será la ruta base de nuestro backend (coincidirá con la propiedad server.servlet.context-path que tendremos en el application.properties de nuestro proyecto Spring Boot).
  • VUE_APP_UMU_CLIENT_APP: indicaremos el nombre de la aplicación, seguido de ui. En el ejemplo vemos cómo está puesta para la aplicación Consulta de Expedientes.

Después, tenemos que añadir a nuestro main.js lo siguiente:

// Front logger
import log from "@mncs/fwjs-components/log";
Vue.use(log);

Con esto ya lo tendríamos configurado. El logger toma el usuario logeado de vuex, por lo que hay que tener en cuenta la siguiente advertencia:

El logger toma el usuario logeado de Vuex, del módulo "user", de la variable de estado "user". Esta es la estructura por defecto del login con el Portal de Servicios, por lo que es importante que la tengamos igual (la podemos ver en Login con JWT en Vue (Portal de Servicios o CAS)).

Configuración backend

En el proyecto Spring Boot, tendremos que seguir los siguientes pasos para incluir el logger del ui. En primer lugar, tenemos que añadir la siguiente dependencia al pom.xml:

<dependency>
	<groupId>es.um.atica.fundewebjs.fundewebjs-api</groupId>
	<artifactId>fundewebjs-lagar</artifactId>
	<version>1.0.0-SNAPSHOT</version>
</dependency>

Además, también en el pom.xml, en el bloque de repositories, tenemos que añadir el siguiente:

<repository>
	<id>fundewebjs.archiva.atica.umu.es</id>
	<name>ATICA - UMU Repository - FundeWebJS</name>
	<url>https://archiva.um.es/archiva/repository/FundeWebJS/</url>
	<releases>
		<enabled>true</enabled>
	</releases>
	<snapshots>
		<enabled>true</enabled>
	</snapshots>
</repository>

En la clase que inicia la aplicación, que será algo como NombreApplication.java, sustituyendo Nombre por el de nuestra aplicación, tendremos que añadir a la clase la anotación @ComponentScan, con el contenido siguiente:

@ComponentScan( basePackages = {
		"es.um.atica.aplicacion", "es.um.atica.fundewebjs"
} )

Ahí, tenemos que cambiar aplicación por el paquete base de nuestra aplicación.

Con esto, un ejemplo de esta clase inicial podría ser el siguiente:

package es.um.atica.pruebaspose;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan( basePackages = {
		"es.um.atica.pruebaspose", "es.um.atica.fundewebjs"
} )
public class PruebasPoseApplication {

	public static void main(String[] args) {
		SpringApplication.run(PruebasPoseApplication.class, args);
	}

}

Por último, en application.properties, tendremos que tener las siguientes propiedades:

##### Logs UI
# FundeWebJS Habilitar endpoint jsn.logger
fdwjs.api.frontLogger.enable=true

# FundeWebJS Habilitar filtro para cabeceras en logs MDC de lagar 
fdwjs.api.lagar.enable=true 
fdwjs.api.lagar.headers=UMU-User-UUID,UMU-Client-APP

# FundeWebJS Habilitar filtro para loggear request/response
fdwjs.api.logging.enable=false
fdwjs.api.logging.client.enable=true
fdwjs.api.logging.query.enable=true
fdwjs.api.logging.headers.enable=true
fdwjs.api.logging.payload.enable=true
fdwjs.api.logging.payload.maxLength=6400
fdwjs.api.logging.url-patterns=*

Estas propiedades también tendrán que estar en los application.properties de los entornos. En estos, ademas, tendremos que comprobar también la propiedad server.tomcat.accesslog.pattern, poniéndole este valor si no lo tiene:

server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" "%{X-Forwarded-For}i" %D "%{UMU-Request-UUID}o"

Funcionamiento y uso del log

Por defecto, se loggearán los warnings y errores que aparezcan en nuestro frontend. Esto se hará sólo cuando la imagen sea de producción, es decir, en los entornos o si ejecutamos la aplicación en local con la opción --mode production. Si en local no utilizamos esa opción seguiremos viendo los errores y warnings en la consola del navegador.

Además, podemos indicar explícitamente logs que queremos que se manden. Por defecto, el nivel de log que registrará el backen es debug; los niveles de log que podemos mandar son:

  • debug
  • info
  • warn
  • error
  • fatal

Para mandar logs explícitamente, lo haremos de las siguientes formas.

Desde un componente, lo podemos hacer llamando a this.$logger, seguido del método correspondiente al nivel de log que queramos mandar:

this.$logger.warn("Log debug");
this.$logger.info("Log info");
this.$logger.warn("Log warn");
this.$logger.error("Log error");
this.$logger.fatal("Log fatal");

En archivos .js, hace falta un paso extra. Tendremos que importar la instancia de Vue, y para ello necesitamos cambiar en el main.js la declaración de ésta, neceistamos exportarla. En el siguiente bloque de código, vemos en primer lugar cómo viene definida por defecto (en proyectos anteriores a esta documentación), y cómo tiene que quedarse:

// Original - Esta hay que cambiarla por la siguiente
new Vue({
  router,
  store,
  i18n,
  render: (h) => h(App),
}).$mount("#app");

// UTILIZAR ESTA:
export const vm = new Vue({
  router,
  store,
  i18n,
  render: (h) => h(App),
})
vm.$mount("#app");

De este modo, en los archivos .js podremos importar la instancia de Vue, y utiliizarla para llamar al logger como en los componentes, pero utilizando vm en vez de this:

import { vm } from "@/main.js";

...

vm.$logger.info("Desde un .js");



  • Sin etiquetas