lunes, 4 de abril de 2011

LogParser 2.2

Como tengo que estudiar el uso que hacen los usuarios de mi aplicación creo que ha llegado el momento de utilizar el log de IIS, y lo cierto es que abrirlo con el notepad y ponerme a puntear todos las entradas se me antoja un poco inviable.

Aunque hay disponibles herramientas de análisis de log de IIS con interfaz gráfica, me gusta especialmente LogParser que permite importar el log de IIS en una base de datos de SQL y después ya somos nosotros mismos quienes a través de consultas SQL tenemos que explotar los datos.

LogParser 2.2 se puede descargar desde http://www.iis.net/community/default.aspx?tabid=34&g=6&i=1976 y también desde
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&displaylang=en

Un buen artículo que habla sobre el programa lo puedes encontrar en http://technet.microsoft.com/en-us/library/bb878032.aspx

Otros enlaces de interés que muestran el uso del programa, http://www.msexchange.org/tutorials/Using-Logparser-Utility-Analyze-ExchangeIIS-Logs.html y http://labloguera.net/blogs/gcarreras/archive/2009/04/30/an-lisis-de-logs-de-iis-utilizando-log-parser.aspx

Lo primero que haremos será ejecutar LogParser.exe con el siguiente comando que nos devolverá el esquema del log de tipo IISW3C que podemos obtener.

LogParser -h -i:IISW3C

En este listado:

  • S es String
  • T es Time
  • I es Integer
  • R es Real

LogFilename (S)

LogRow (I)

date (T)

time (T)

c-ip (S)

cs-username (S)

s-sitename (S)

s-computername (S)

s-ip (S)

s-port (I)

cs-method (S)

cs-uri-stem (S)

cs-uri-query (S)

sc-status (I)

sc-substatus (I)

sc-win32-status (I)

sc-bytes (I)

cs-bytes (I)

time-taken (I)

cs-version (S)

cs-host (S)

cs(User-Agent) (S)

cs(Cookie) (S)

cs(Referer) (S)

s-event (S)

s-process-type (S)

s-user-time (R)

s-kernel-time (R)

s-page-faults (I)

s-total-procs (I)

s-active-procs (I)

s-stopped-procs (I)

 

 

De este modo, crearemos una tabla en nuestro servidor a partir de la información anterior para albergar los datos que queremos importar.

CREATE TABLE [dbo].[IISW3C](

            [LogFileName] [nvarchar](500) NULL,

            [LogRow] [int] NULL,

            [Date] [datetime] NULL,

            [Time] [datetime] NULL,

            [ClientIPAddress] [nvarchar](500) NULL,

            [UserName] [nvarchar](500) NULL,

            [ServiceName] [nvarchar](500) NULL,

            [ServerName] [nvarchar](500) NULL,

            [ServerIPAddress] [nvarchar](500) NULL,

            [ServerPort] [int] NULL,

            [Method] [nvarchar](500) NULL,

            [URIStem] [nvarchar](500) NULL,

            [URIQuery] [nvarchar](500) NULL,

            [HTTPStatus] [int] NULL,

            [HTTPSubstatus] [int] NULL,

            [Win32Status] [int] NULL,

            [BytesSent] [int] NULL,

            [BytesRecivied] [int] NULL,

            [TimeTaken] [int] NULL,

            [ProtocolVersion] [nvarchar](500) NULL,

            [Host] [nvarchar](500) NULL,

            [UserAgent] [nvarchar](500) NULL,

            [Cookie] [nvarchar](500) NULL,

            [Referrer] [nvarchar](500) NULL,

            [s-event] [nvarchar](500) NULL,

            [s-process-type] [nvarchar](500) NULL,

            [s-user-time] [real] NULL,

            [s-kernel-time] [real] NULL,

            [s-page-faults] [int] NULL,

            [s-total-procs] [int] NULL,

            [s-active-procs] [int] NULL,

            [s-stopped-procs] [int] NULL

) ON [PRIMARY]

 

Ahora que ya sabemos el formato de log y tenemos una tabla donde guardar los registros, sólo queda ejecutar el comando preciso para importar los datos en nuestra tabla.

LogParser "SELECT * INTO IISW3C FROM C:\WINDOWS\system32\LogFiles\W3SVC1\ex*.log"
/o:SQL -server:NombreServidor
/driver:"SQL Server"
/database:NombreBaseDatos
/username:NombreUsuario
/password:Password
/iCheckpoint:MyChekPoint.lpc
/i:IISW3C

·         "SELECT * INTO IISW3C FROM
C:\WINDOWS\system32\LogFiles\W3SVC1\ex*.log"
es una consulta que devuelve todos los registros del log del tipo IISW3C para el IIS consultado.

·         /o:SQL –server:NombreServidor /driver:”SQL Server” /database:NombreBaseDatos /username:NombreUsuario y /password:Password son argumentos para la cadena de conexión que utilizará LogParser.

·         /iCheckpoint:MiFichero.lpc es importantísimo, porque permite que sucesivas llamadas a este mismo comando sólo importen los nuevos registros. De hecho, después de esta primera llamada veremos cómo se crea este fichero en el directorio de LogParser (por el tamaño de este fichero no te preocupes, porque ocupa poco).

·         /i:IISW3C especifica el formato de log a importar.

Después de esto, ya podremos poner en juego todo nuestro conocimiento de Sql para consultar nuestra tabla con todos los registros de log.

Sí no queremos importar todo el log de nuestro IIS y queremos filtrar a algún directorio o aplicación en particular, la única solución que he encontrado es agregar una WHERE a la consulta de selección. Por ejemplo:

SELECT * INTO IISW3C FROM C:\WINDOWS\system32\LogFiles\W3SVC1\ex*.log WHERE cs-uri-stem LIKE ‘%%/MiAplicación/%%’

Es interesante ver que hay que poner 2 porcentajes en vez de 1, porque sino LogParser interpreta una variable de reemplazo en vez de un literal porcentaje. Puedes ver más información en http://forums.iis.net/t/1145741.aspx

Si te sirve como referencia, hace poco tiré este script en un servidor en producción y los resultados fueron estos:

image

Es decir, casi 10 millones de filas importadas en 1 hora y media, y la base de datos creció hasta los 3 GB el fichero .mdf y 10 GB el fichero .ldf. Sin embargo, el directorio C:\WINDOWS\system32\LogFiles\W3SVC1 sólo ocupada 1 GB. Está claro que IIS necesita menos espacios para guardar los registros que SQL.

Un saludo!.

Error en PostBack en página por defecto

Está claro que esta semana va a ser la semana de los posts “estoy subiendo una aplicación a un servidor dedicado y me encuentro problemas variopintos”.

En esta ocasión ha sido un problema (perdón, quise decir issue) que tiene ASP.NET y que consiste en que si se accede a la aplicación sin especificar el nombre de página (por ejemplo, panicoenlaxbox.com en vez de panicoenlaxbox.com/default.aspx) los eventos asociados en el código del servidor no se enlazan. Es decir, pones un botón en la página .aspx y enlazas un manejador en código de la página y éste nunca se engancha a no ser que se haya especificado el nombre de página.

No me preguntes porqué porque esto me parece un super “issue”, bueno en realidad me parece un “bug”… en realidad es algo incomprensible y que es la primera vez que me pasa, así que no es muy reproducible, pero bueno…

La solución la encontré aquí (menos mal que este caballero también escribe un blog sino todavía estoy tirándome de los pelos). De hecho, poco más información he podido encontrar al respecto, sino hilos de gente desesperada como este.

Mi solución ha pasado por un híbrido entre la solución primera y la mía propia, un poco menos agresiva creo, ya que en vez de hacer un Redirect a la página por defecto lo que hago es establecer la propiedad Action del formulario.

    Private Sub _Default_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not IsPostBack Then

            Dim newUrl As String = GetASPNETPostbackOnDefaultPage()

            If Not String.IsNullOrEmpty(newUrl) Then

                Form.Action = newUrl

            End If

        End If

    End Sub

 

    Public Function GetASPNETPostbackOnDefaultPage() As String       

        Dim defaultPage As String = "default.aspx"

        Dim rawUrl As String = Request.RawUrl

        If rawUrl.ToLower().IndexOf(defaultPage) < 0 Then

            Dim newUrl As String

            If rawUrl.IndexOf("?") >= 0 Then

                ' URL contains query string

                Dim urlParts As String() = rawUrl.Split("?".ToCharArray(), 2)

                newUrl = urlParts(0) & defaultPage & "?" & urlParts(1)

            Else

                newUrl = If((rawUrl.EndsWith("/")), rawUrl & defaultPage, rawUrl & "/" & defaultPage)

            End If

            Return newUrl

        Else

            Return String.Empty

        End If

    End Function

 

Un saludo!

Configurando nuestra aplicación con system.webServer

 

Como decía en un post anterior, ahora los desarrolladores de ASP.NET en IIS 7.0 o superior tenemos la posibilidad de configurar el servidor web directamente desde nuestros ficheros web.config de aplicación.

 

Por ejemplo y para ilustrar el uso de algunas de las características más habituales de configuración del servidor, vamos a establecer desde nuestro fichero web.config las siguientes propiedades:

 

·         Agregar una meta para el modo de documento en IE.

·         Establecer el documento predeterminado.

·         Habilitar la compresión dinámica.

 

Para ello hay que incluir lo siguiente en nuestro fichero web.config.

 

  <system.webServer>

 

    <httpProtocol>

      <customHeaders>

        <clear/>

        <add name="X-UA-Compatible" value="IE=8" />

      </customHeaders>

    </httpProtocol>

 

    <defaultDocument enabled="true">

      <files>

        <clear />

        <add value="Default.aspx" />

      </files>

    </defaultDocument>

 

    <urlCompression doDynamicCompression="true" />

 

  </system.webServer>

 

Agregar una meta para el modo de documento en IE.

http://msdn.microsoft.com/en-us/library/cc288325(v=vs.85).aspx

 

Establecer el documento predeterminado.

http://www.iis.net/ConfigReference/system.webServer/defaultDocument

 

Habilitar la compresión dinámica.

http://www.iis.net/ConfigReference/system.webServer/urlCompression

 

Con el anterior código, ya no tendremos que establecer estas características desde IIS cada vez que subamos nuestra aplicación. Además, en entornos de hosting donde no tenemos acceso a la consola de administración de IIS, algunas de estas opciones serían imposible de asignar.

 

En definitiva, estas 3 características se verán en IIS de la siguiente forma:

 

clip_image001

clip_image002

 

clip_image003

 

Poquito a poco configuramos nuestro servidor.

 

Un saludo!

Modo de documento en IE

Recientemente hemos adquirido un servidor dedicado en un hosting para alojar un nuevo sitio web. Mi sorpresa ha sido mayúscula cuando al servir las páginas a IE estas se muestran con el modo de documento IE7.

Para más información sobre los modos de documento disponibles, visita este enlace http://msdn.microsoft.com/en-us/library/cc288325(v=vs.85).aspx

clip_image002

Yo desde luego no estoy forzando esta “renderización” en ningún sitio, así que alguien tenía que estar haciéndonos “mobbing”.

Mi primera respuesta es confirmar que esto sucede por un motivo concreto, así que con ayuda de fiddler encontramos el motivo:

clip_image003

Sabiendo ya que para todo hay una explicación lógica, mi siguiente paso es ir al servidor para observar que mi sitio web está heredando esa “meta” directamente del nodo más superior (el servidor).

clip_image005

clip_image007

Lo cierto es que esta “meta” no me parece adecuada y no sé quién ha tenido la feliz idea de incluirla (¿quizás el panel de control Paralles?). En cualquier caso y como no me apetece tocar nada en el servidor, la solución pasa por incluir el siguiente código a nuestro fichero web.config de la aplicación.

            <system.webServer>

                        <httpProtocol>

                                   <customHeaders>

                                               <clear />

                                               <add name="X-UA-Compatible" value="IE=8" />

                                   </customHeaders>

                        </httpProtocol>

            </system.webServer>

clip_image009

Fijarse que tan importante es “añadir” la cabecera como “eliminar” previamente cualquier cabecera, ya que si no “elimináramos” previamente las cabeceras obtendríamos un error por cabecera duplicada (la que se hereda del servidor y la que hemos metido nosotros).

clip_image011

Un saludo!.

sábado, 2 de abril de 2011

HTML, XHTML y CSS (el porqué)

 

La verdad es que me llevo pegando con HTML y CSS desde hace muchos años. No soy diseñador web, tampoco soy programador web, soy simplemente programador, pero como hoy en día todos estos roles están muy difusos y al que programa una aplicación de escritorio igualmente se le pide que programe una aplicación web, y ya puestos que la diseñe y además la posicione en google, pues creo oportuno hacer una revisión de mis conocimientos de HTML y CSS.

La serie de post sobre HTML y CSS que tengo previsto publicar responde al hecho de que creo que ha llegado el momento de “aprender correctamente” HTML y CSS. ¿Por qué nunca se estudia HTML y CSS al igual que sí se estudiar VB.NET, C# o cualquier otro lenguaje de programación? Creo que el error está en que cualquiera puede hacer una página web en minutos (ya sea a través del diseñador WYSIWYG de turno o de alguna herramienta on-line), mientras que hacer una aplicación de escritorio requiere una curva de aprendizaje mucho mayor y “mi prima” no puede hacerla en una tarde. Otro problema es que los navegadores son muy permisivos con nuestros errores y se comen casi todo… ¿Seguro que eres de esos que escribe <span style=”font-weight: bold”>Resaltado</span> en vez de <strong>Resaltado</strong>? ¿Peor aún, puede ser que no sepas que es la instrucción DOCTYPE? ¿O el modo quirk de un navegador? ¿Sabes que existe XHTML?

Está claro que a día de hoy conozco el uso y significado de las principales etiquetas HTML (porque no nos engañemos, no conozco a nadie que haya usado alguna vez, por ejemplo,  la etiqueta <cite>, que claro está tiene un significado que deberíamos conocer). También conozco el uso de casi todas las propiedades CSS (estoy hablando de CSS 2.1, el CSS 3 aún no lo tengo fichado) y sin embargo y aún teniendo todas las piezas del puzle ¿Realmente sé HTML y CSS? ¿Sé separar contenido de presentación? ¿Conozco el modelo de presentación visual y el modo de cajas (vital para entender la estructura de una página)?

A lo mejor tú eres un gurú de todo esto y ya lo tienes claro, pero para mí y para algunos otros, seguro que es de utilidad.

Lo dicho, en las siguientes semanas espero que “lluevan” post de HTML y CSS.

Un saludo!.