Archivo mensual: marzo 2013

Moving log4js-ext development from Windows to Linux -while keeping Windows dev supported

I have been moving my development environment from Windows to Linux, step by step, and the time for moving log4js-ext has arrived.

Log4js-ext is a pure javascript + Java project, and therefore source code portability is not a big issue: the only portability issues that arose were due to the build tools I use to create the deliverables, and the ant build file.

Issues

Here is my main issues list:

  • Differences in OS conventions, including directory separator, etc., make tools fail.
  • Can’t use good old CMD to run command line tools.
  • Some tools are not available in the Linux world.
  • Other nuisances.

Differences in OS conventions, including directory separator character, etc.

There are differences in the way Linux and Windows names things, case sensitivity or the directory separator.

Being aware of that, and knowing that Windows supports both ‘\’ and ‘/’ as directory separators, I’ve been using ‘/’ for ages, so that did not pose a problem.

Besides, some file paths changed (i.e., the Tomcat config directory location), but that was an easy thing to spot and fix, and I moved those paths to ant properties to make them easier to deal with.

Thankfully, no other issues appeared in this area.

Can’t use good old CMD to run command line tools

While the project was hosted in Windows, I added calls to external tools to generate Javascript API documentation, optimize image size, etc,. invoking cmd.exe with the ant exec task.

For example, this is the relevant part of the ant code I used to generate the API documentation:

<exec executable="cmd" dir="${lib.basedir}/src" >
  <arg line="/c jsduck .../>
</exec>

I had to modify the exec to make it work both in Windows and Linux, as follows:

<!-- Ok, executables are called differently in Windows and Linux... -->
<condition property="jsduck.cmd" value="cmd.exe">
  <os family="windows"/>
</condition>
<property name="jsduck.cmd" value="jsduck"/>

<condition property="jsduck.cmd.extraparams" value="/c jsduck">
  <os family="windows"/>
</condition>
<property name="jsduck.cmd.extraparams" value=""/>

<exec executable="${jsduck.cmd}" dir="${lib.basedir}/src" >
  <arg line="${jsduck.cmd.extraparams} .../>
</exec>

As you can see, I had to provide slightly different commands to exec. It was easy, but I have to admit that ant makes this verbose and to look like a big thing -which it is not.

Another annoyance was running java to minify the consolidated javascript file that includes all of log4js-ext. In Windows, I used an exec task to call Java, passing the YUI minifier jar, as follows

<exec executable="cmd">
  <arg line="/c java -jar ${yui.jar}
   ${pack.tmpdir}/${lib.project}-all-dev.js
   -o ${pack.tmpdir}/${lib.project}-all.js"/>
</exec>

Now, I decided to use the ant java task instead, as it looked easier to use it in a portable way:

<java classpath="${log4j.jar}" jar="${yui.jar}"
  spawn="true" fork="true">
  <arg line="${pack.tmpdir}/${lib.project}-all-dev.js -o
     ${pack.tmpdir}/${lib.project}-all.js"/>
</java>

However, I discovered that I had to fork the java task in order to invoke a jar, and that meant that other operations were executed *in parallel*…and therefore were called before the java task output they required was available, failing.

The workaround was to add the following lines immediately after the java task, so that it waited until the generated file was available, or 30 seconds, whatever came first:

<waitfor maxwait="30" maxwaitunit="second">
  <available file="${pack.tmpdir}/${lib.project}-all.js"/>
</waitfor>

Thank God, the problem with parallel execution was easily repeatable and I was able to find the problem in no time. Had it manifested itself only from time to time, it would had been a real pain.

Some tools are not available in the Linux world

Too bad, but it is true: some tools that are readily available in the Windows world are not there in the Linux world.

That was the case with the tools I use to optimize PNG, GIF and JPG images, pngslim and pngout.

Well, since log4js-ext is very mature when it comes to the front-end, there is no real need to optimize new images, which will probably never come into being. The smart thing to do was to ignore the problem, and not to look for alternatives 🙂

So, that’s what I placed at the beginning of the corresponding ant task:

<fail message="NOT PORTED TO LINUX TOOLS: if the need arises to add new images, then it will make a lot of sense to look for alternatives that work in Linux"/>

Call me pragmatic!

Other issues

Whenever you move or install a complex development environment, it is always hard to reproduce it exactly, unless you go to great lengths.

Log4js-ext being a personal project, that was asking too much, and I just installed the latest versions of the different tools in Linux.

That meant I found the typical problems due to my Windows environment using version x.y.1 of JSDuck and Linux apt-get installing x.y.2: in fact, I had not one, but two problems related to using a newer version of JSDuck.

I know, this is not related to Windows vs Linux per se, but it is worth taking into account because it will happen. For big projects this can be a real problem, and I tend to be very, very strict with the exact version of tools and libraries I use.

A non-trivial ant build file that works in Linux *and* Windows

Just for the sake of it, I run the new ant file in Windows and performed several tests to check the results: everything worked, so I called it a day.

All in all, making my build and test scripts work in Windows and Linux was not as much of a chore as I had anticipated, and I was pleased with the time it took to migrate and the result.

Anuncios

Log4js-ext 2.0 is out!

I have added a major feature to log4js-ext, remote logging support, that allows sending log data to your remote web server.

There is built-in support for all major Java logging frameworks: Log4j, Slf4j and Apache Commons Logger. To learn how to use it, visit this link.

Another major addition to log4js-ext 2.0 is a powerful search & highlight feature to log4js-ext log window: now, it is possible for you to filter logs, and then perform fine grained searches for specific values.

If you click the image below, you will see that there is a new search toolbar, and that the logged text is highlighted in several log entries: this is a real time saver when digging into a ton of data.

search and highlight

To make life easier I am hosting the API documentation online.

Log4js-ext is developed using Test Driven Development, to guarantee is is a high quality product. Want proof? Take a look at the test results for version 2.0.

Log4js-ext is Open Source, you can download and start using it now, free of charge.

Enjoy!

Introducción al control de versiones, usando Git: Pragmatic version control with Git

Ahora mismo, si alguien me pidiera opinión sobre qué control de versiones usar, y qué libro utilizar para iniciarse en el uso de un sistema de control de versiones, la respuesta sería “usa Git, y echale un vistazo a Pragmatic version control using Git“.

El libro va al grano, sin perderse por vericuetos, y sobre todo sin perder de vista que un sistema de control de versiones es un medio para un fin: primero, pues, viene la necesidad concreta, y después lo que un sisteam como git nos ofrece para satisfacer esa necesidad.

Demasiado a menudo nos cuentan el cómo sin que se vislumbre el por qué:  no es el caso de ese libro, que nunca pierde de vista el por qué de las cosas.

Por otro lado, si ya tienes experiencia con el uso de un sistema de control de versiones, tampoco te irá mal un libro que une muy rapidamente la necesidad concreta (¿cómo creo una rama aparte para “trastear”?) con lo que git proporciona para satisfacerla.

Finalmente, si eres un super experto…busca en otro lado. Estamos ante un libro de poco más de 150 páginas, simplemente no puede serlo para todo el mundo.

Una introducción excelente tanto a los sistemas de control de versiones como a git, ideal para programadores que tengan ninguna o poca experiencia con ambas cosas.

Remote logging for log4js-ext 2.0

The biggest new feature in log4js-ext 2.0 is its support for remote logging to Java web apps.

Providing this feature means that you can perform logging in your ExtJs javascript code, and send it to the server too, where logs will be routed to Log4j, Slf4j or the Apache Commons Logger. All of them are supported.

Configuration: the server side

Steps to add server side support to your Java web app:

  1. Add log4js-ext-remoting-xxx.jar to your Java app -yes, xxx is the library version
  2. Configure the remote logging servlet, as follows:
    <servlet>
      <servlet-name>Log4jsExtServlet</servlet-name>
      <servlet-class>com.softwarementors.log4jsext.remote.Log4jsExtServlet
      </servlet-class>
    
      <servlet-mapping>
        <servlet-name>Log4jsExtServlet</servlet-name>
        <url-pattern>/remotelogrequest</url-pattern>
      </servlet-mapping>
    </servlet>
    

That’s it!

Of course, you will have to provide the logging jars for Log4j, Slf4j or the Apache Commons Logger -but you already knew that!

Configuration: the client side

You can keep your current logs as they are, there is no need to modify your logging code in the client side. That transparency is one of the reason why you are using log4js-ext for your logging needs.

All you need to do is register one or more of the new appenders: they know how to send log data to your remote application.

Here is source code that registers appenders for Log4js, Slf4j and Apache Commons Logger with the root logger: this causes all client side logs to go to the remote web app by default.

// Configure simple remote logging
Sm.log.Logger.getRoot().addAppender(
  Sm.log.remote.RemoteAppender.createLog4jAppender(
    "/log4js-ext/remotelogrequest") );
Sm.log.Logger.getRoot().addAppender(
  Sm.log.remote.RemoteAppender.createSlf4jAppender(
    "/log4js-ext/remotelogrequest") );
Sm.log.Logger.getRoot().addAppender(
  Sm.log.remote.RemoteAppender.createApacheCommonsLoggingAppender(
    "/log4js-ext/remotelogrequest") );

Now, if this has not convinced you of the power of log4js-ext, I don’t know what will do…

Cambio de discos y reinstalación de GRUB2 en el MBR

Este mes ha tocado renovar infraestructura, e instalar un SSD más grande para las máquinas virtuales con mis proyectos, que siempre tengo en un disco extraíble conectado vía eSata/USB 3.0: de este modo siempre puedo trabajar en casa, con mi portátil, o en máquinas de terceros.

El nuevo SSD es un Sandisk Extreme de 480 Gb, con el doble de espacio que el Samsung 830 donde residían las máquinas virtuales, que ha ido a convertirse en el disco principal, sustituyendo al “viejo” Intel X25-M de 160 Gb.

Migración a un nuevo disco

La migración del disco viejo al nuevo ha ido sin problemas, tanto las particiones de Windows como las de Linux.

Para migrar el disco utilicé Paragon Backup & Recovery, escogiendo hacer una copia completa de todo el disco, ya que la copia partición a partición me dio problemas.

El único inconveniente fue tener que restaurar Grub en el MBR, que es quien se encarga de permitirme decidir si arranco con un sistema operativo o con otro.

Reinstalar Grub

Para restaurar Grub tuve que dar los siguientes pasos:

  • Arrancar con el CD del Linux que tengo instalado e irme a la línea de comandos.
  • Averiguar cuál es el disco donde se encuentra Linux: para ello, basta con listar los dispositivos, con ls /dev/sd?. En mi caso, el disco era sda
  • Averiguar cuál es la partición donde reside Linux: para ello, basta con mirar las particiones del disco, con cfdisk /dev/sda. En mi caso era sda5
  • Montar dicha partición: install -d /mnt/z y luego mount /dev/sda5 /mnt/z
  • Reinstalar grub: para ello, grub-install --root-directory=/mnt/z /dev/sda

Una vez hecho esto, bastó con arrancar de nuevo, y voilá -a pesar de algunos mensajes de queja del sistema.

Rendimiento

Tengo que confesar que no he notado ninguna diferencia en la velocidad entre el Sandisk, el Samsung (ambos SATA III) y el Intel, este último de una generación anterior y SATA II.

Y es que los SSDs de las dos/tres últimas generaciones, aunque bastante diferentes en prestaciones en la teoría, no muestran ninguna diferencia notable en el día a día de un desarrollador, ni aún cuando tengo dos o tres máquinas virtuales en marcha.

A decir verdad, no es algo que no esperase: de hecho, el cambio de discos ha venido motivado por la necesidad de tener mayor espacio, no por un tema de rendimiento.

Medir consumos de energía con el ZM31

Como estoy jugando con la idea de poner una máquina que me haga de NAS y servidor web 24 horas al día, me ha parecido buena idea comprar un medidor de consumo para ver cuánto consume dicha máquina, y ver el efecto real de poner el equipo en suspensión, apagar los monitores automáticamente, etc.

Y es que si no se va con cuidado, al final del año y con un funcionamiento 24×7 puede resultar más caro tener tu máquina que pagar un hosting decente.

La cosa es que las instrucciones del medidor han venido solo en alemán, y encontrar el manual en inglés ha sido una auténtica odisea, con el añadido de que el inglés deja mucho que desear.

Así que aquí están las instrucciones del medidor de consumo Interterk ZM31 (o ZM 31), con código de fabricante IN16618B. Igual algún otro comprador en apuros las encontrará, y de paso yo también tendré las instrucciones a mano dentro de unos meses.

¿Qué puedo medir con el ZM31?

Pues se pueden ver varias cosas, y se cambia de “vista” pulsando el botón MODE. Las “vistas” que hay son:

  • kWh: kilowatios hora consumidos desde que empezamos a registrar. Ver más abajo esto del registro de información.
  • costs: coste de lo consumido, puede usar dos tarifas distintas que se pueden modificar. Ver más abajo.
  • W: watios que se están consumiendo en este momento.
  • W LO: watios máximos consumidos desde que empezó a registrar.
  • W HI: watios mínimos consumidos desde que empezó a registrar.

¿Cómo empiezo a registrar datos de kwh, consumo y registro de watios máximos/mínimos, y cómo pongo a cero estos valores de nuevo?

Para comenzar a registrar consumo: pulsar STA/STP. Las lecturas de kwh y los consumos se acumularán, y las lecturas mínima y
máxima de potencia (watios) se irán actualizando.

Para poner a cero/resetear y parar de registrar datos: pulsar MODE + STA/STP durante 2 segundos. Hasta que volvamos a poner en modo registro no se volverá a registrar ni consumo ni valores máximo/mínimo de potencia (W).

Lógicamente, para algo como ver la potencia máxima y mínima que consume tu ordenador u otro aparato, conéctalo primero y poner en funcionamiento, y solo entonces resetea el medidor de consumo: de lo contrario, la lectura mínima de potencia siempre será cero.

¿Cuánto tiempo se ha estado conectado a la corriente vs cuánto tiempo he estado registrando el consumo, aún desconectado?

Pulsando el botón ON TIME se conmuta entre el tiempo que llevamos registrando (en la pantalla aparece ‘REC’) y el tiempo que realmente ha estado conectado el dispositivo (en la pantalla aparece ‘ON’), que será el mismo o menos, lógicamente.

Es posible detener/continuar el registro pulsando STA/STP. Atención, que esto para el tiempo registrado *y* el tiempo de conexión.

¿Cómo cambio la tarifa, para que calcule correctamente el consumo?

Pulsar MODE + ON TIME + STA/STP durante 4 segundos: entrará en modo edición de consumo.

Mientras estamos en este modo, podemos usar ON TIME y STA/STP para cambiar el valor de un dígito y para pasar de un dígito a otro. No he anotado cuál es cuál, así que os tocará hacer I+D.

Cuando terminemos, pulsar MODE, y se grabará la tarifa.

Hay dos tarifas distintas, ¿cómo escojo una u otra?

Cuando se esté en la “vista” de consumo (costs), pulsar MODE 4 segundos, y veremos que conmuta a la otra tarifa.

Cloud Foundry y Micro Cloud Foundry para desarrolladores Spring

Las últimas semanas he estado colaborando en un interesante proyecto, una prueba de concepto que incluía entre otras cosas el uso la infraestructura de Cloud Foundry para proyectos con Spring en el backend -parte de la que se ha encargado un servidor.

¿Qué es Cloud Foundry, sin marketing y para un desarrollador?

Cloud Foundry es una iniciativa detrás de la que está VMware como gran esponsor, y que ofrece soporte para ‘cloudificar’ nuestras aplicaciones con la consiguiente escalabilidad, estandarización de la infraestructuda y todo eso.

Dejando aparte los discursos de estrategia y márketing, y centrándonos en el impacto para los desarrolladores Spring, la cosa apenas se complica mucho por ello. Y esa es la gran virtud.

Cloud Foundry proporciona una infraestructura estable y estándar (p.ej. Java 1.6 o 1.7, tc Server/Tomcat, Spring, etc.) que incluye diversos servicios (MySql 5.1, Redis, etc.), contra la que podemos desarrollar y desplegar nuestras aplicaciones.

Para los desarrolladores existe la posibilidad de usar como sustituto de la cosa real una máquina virtual que proporciona toda la infraestructura y servicios de Cloud Foundry, y que podemos usar para desarrollar en local. Básicamente es a esto es a lo que se llama Micro Cloud Foundry, ni más ni menos.

Vale, pero ¿cómo afecta todo esto a mi código Spring? Pues en muchos casos el impacto es cero: por ejemplo, en nuestra aplicación se ataca una base de datos MySql, digamos ‘killer_demo’, con el usuario ‘myUser’ y la password ‘pwd’. ¿Qué cambios hice con respecto a una aplicación Spring a desplegar en nuestro propio entorno? Cero. En mi caso utilicé Spring beans para atacar MySql, usando la siguiente configuración

    <beans:bean id="springDataSource" 
     class="org.apache.commons.dbcp.BasicDataSource">
       <beans:property name="driverClassName" 
          value="com.mysql.jdbc.Driver" />
       <beans:property name="url" 
          value="jdbc:mysql://localhost/killer_demo" />
       <beans:property name="username" value="myUser" />
       <beans:property name="password" value="pwd" />
    </beans:bean>

    <beans:bean id="springEmf"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <beans:property name="persistenceUnitName" 
           value="killer_demo_pu"/>
        <beans:property name="persistenceProviderClass" 
           value="org.hibernate.ejb.HibernatePersistence"/>
        <beans:property name="dataSource" 
           ref="springDataSource"/>
    </beans:bean>

La cosa es que cuando enviamos la aplicación a un sistema que soporte Cloud Foundry, el correspondiente mecanismo automágico le echa un vistazo a los Spring beans y los reconfigura. Así, el sistema ve que tenemos una fuente de datos que utiliza un usuario ‘myUser’ y una contraseña ‘pwd’: si no existe una base de datos la crea automáticamente, con un nombre que se saca de la manga, y por supuesto trabaja con usuarios y contraseñas generados del mismo modo.

Y lógicamente sustituye los valores proporcionados por nosotros por los valores que se ha sacado de la manga en los propios beans.

Obviamente, si la configuración de la aplicación se complica o deseamos un mayor control, puede llegar a ser necesario dar información específica a Cloud Foundry, información que se proporcionará vía configuración de Spring. Aún así, el impacto en el resto del código fuente será cero.

Como os podéis imaginar, la cosa funciona de forma similar si en lugar de usar Java+Spring se usa otra infraestructura soportada, como Scala, Grails, Node.js, etc.

¿Y cómo configuro o despliego aplicaciones en Cloud Foundry?

Para tareas tales como desplegar y configurar la aplicación (¿cuánta memoria le vamos a dar?) y los servicios que usa, deberemos utilizar vmc o el correpondiente plugin de Eclipse.

Por ejemplo, para instalar myApp.war por primera vez, tendremos que ejecutar

vmc push myApp

O, para ver las aplicaciones instaladas, bastará con

vmc apps

Desde luego, puede ser necesario controlar el entorno de manera mucho más fina por parte de un administrador, y este puede obtener acceso a los distintos servicios mediante tunneling, algo que no tiene por qué afectar al código fuente.

Micro Cloud Foundry está muy bien, pero…

… eso de tener que enviar un war con los cambios mientras desarrollas no es que favorezca el desarrollo ágil, la verdad.

Personalmente prefiero desarrollar mis aplicaciones en local, dado que me permite un desarrollo mucho, mucho más ágil: si se hace con cuidado, se puede desarrollar sin problemas la aplicación contra un Tomcat local, una base de datos local y cualesquiera otros servicios locales, y luego moverla a Micro Cloud Foundry para verificar que no hemos hecho nada raro.

Un detalle puntual: dado que Micro Cloud Foundry instala nuestra aplicación como si fuera la ROOT de Tomcat, no importa cómo llamemos al WAR que desplegamos, será conveniente que configuremos nuestra aplicación y el Tomcat local para que tenga esto en cuenta: aquí hay información relevante al respecto.