Identificando los servicios en un proceso Svchost

Svchost.exe es un proceso genérico que contiene múltiples servicios. Además de que pueden ejecutarse múltiples instancias de Svchost.exe al mismo tiempo.

Podemos identificar los servicios dentro de los procesos Svchost usando el comando Tasklist, y si queremos realizarlo con más profundidad con Process Explorer de las sysinternals.

Con tasklist y el parámetro /svc obtenemos un listado (que podemos redirigir a un archivo de texto) de los servicios, mostrando los que se ejecutan dentro de procesos.

svchostSERVICES02

En la salida de este parámetro obtenemos los PID de los procesos, con el que podemos determinar los puertos que utilizan, con simplemente compararlo con la salida del comando netstat -a -o -n.

Con Process Explorer, una vez abierta la utilidad, clic derecho sobre el proceso svchost que deseamos, elegimos propiedades y de la ventana la pestaña Services.

svchostSERVICES

Resolver los problemas de los Servicios

A pesar de si la raíz de un error es problema de hardware o de software, necesitamos un plan fiable para resolución de problemas. Un plan efectivo comienza reuniendo información, observando los síntomas y un buen estudio.

Cuando resolvemos problemas de los servicios, necesitamos disponer de un plan preparado para determinar la causa del problema en el servicio y decidir que herramientas necesitamos para aislarlo y resolverlo, Yes we can!

Los errores pueden ser de inicio, detención y bastantes más tipos, aunque los más comunes nos sueltan los errores:

  • ERROR_SERVICE_LOGON_FAILED
  • ERROR_SERVICE_DEPENDENCY_FAILED
  • ERROR_SERVICE_START_HANG

Como ya hemos comentado varias veces, seremos capaces de elegir diversas maneras de solucionar o depurar el problema del servicio.

Herramientas

La herramienta más eficiente para la comprobación y depuración de los servicios es sc.exe. Podemos usarla para establecer las propiedades almacenadas en el registro de un servicio  para controlar cómo se inician durante el arranque y cómo se ejecutan en procesos en segundo plano.

Mientras se desarrolla y depura un servicio, esta herramienta puede ayudar ya que ofrece un generoso interfaz en línea de comandos para todas las opciones de control del servicio y puede fácilmente usarse en scripts.

Sc.exe es una herramienta de desarrollo que proporciona más información exacta y detallada sobre los servicios que las dos herramientas que proporciona el propio servicio operativo. El complemento services.msc y la herramienta en línea de comandos, Net.exe, pueden decirnos que un servicio se está ejecutando, o si está detenido o pausado. La herramienta sc.exe ayuda a la diagnosis del servicio cuando deja de responder.

Sc.exe nos permite consultar el estado del  servicio y recuperar los valores almacenados en la estructura de los campos de estado. Net.exe y Services.msc no nos proporcionan el estado completo del servicio. Sc.exe, sin embargo nos dice exactamente su estado además de mostrarnos el número del último control y un indicio de espera. El control puede entonces utilizarse como una herramienta de depuración ya que proporciona una indicación clara de en qué medida durante la inicialización había progresado antes de dejar de responder.

Sc.exe también permite la llamada de cualquier API de control de servicio y variedad de parámetros desde la línea de comandos. Esto nos da varias ventajas. Nos proporciona la facilidad una manera de crear o configurar la información de un servicio en el registro y en la base de datos de SCM. No necesitamos configurar el servicio manualmente, creando entradas en el registro y reiniciando el equipo para que la base de datos SCM se actualice.

ADVERTENCIA:No deben modificarse las claves y subclaves de los servicios directamente en el Registro ya que podríamos causar resultados impredecibles en el inicio, detención o control de los mismos.

Como herramienta en línea de comandos, sc.exe también puede utilizarse para comprobar los servicios, podemos crear archivos de lotes (batch) con llamadas a sc.exe con varios parámetros que controlen el servicio. Útil si queremos ver el comportamiento de los servicios cuando se detienen y reinician repetidamente.

sc <equipo> [comando] [nombre_servicio] <opción1> <opción2> …
<equipo> = Sólo si es remoto y en formato \nombreEquipo

Comandos:

[comando] Descripción
query Consulta el estado de un servicio si va seguido de un nombre de servicio. Enumera el estado de todos los servicios si no va seguido de un nombre de servicio.
queryex Consulta el estado extendido de un servicio si va seguido de un nombre de servicio. Enumera el estado extendido de todos los servicios si no va seguido de un nombre de servicio.
start Inicia un servicio
pause Envía una solicitud de control PAUSE a un servicio
interrogate Envía una solicitud de control INTERROGATE a un servicio
continue Envía una solicitud de control CONTINUE a un servicio
stop Envía una solicitud de STOP a un servicio
config Cambia la configuración de forma persistente de un servicio
description Cambia la descripción de un servicio
failure Cambia las acciones que emprende un servicio en caso de error
failureflag Cambia el marcador de acciones de error de un servicio
sidtype Cambia el SID de servicio de un servicio
privs Cambia los privilegios requeridos de un servicio
qc Consulta la información de configuración de un servicio
qdescription Consulta la descripción de un servicio
qfailure Consulta las acciones que emprende un servicio en caso de error
qsidtype Consulta el tipo de SID de servicio de un servicio
qprivs Consulta los privilegios requeridos de un servicio
delete Elimina un servicio del Registro
create Crea un servicio (lo agrega al Registro)
control Envía un control a un servicio
sdshow Muestra un descriptor de seguridad de un servicio
sdset Envía el descriptor de seguridad de un servicio
showsid Muestra la cadena SID de servicio correspondiente a un nombre arbitrario
GetDisplayName Obtiene el DisplayName de un servicio
GetKeyName Obtiene el ServiceKeyName de un servicio
EnumDepend Enumera las dependencias del servicio

Comandos que no necesitan un nombre de servicio:

sc <equipo> [comando] <opción>

boot (ok|bad) Indica si el último arranque debe guardarse como última configuración conocida de arranque correcto.
Lock Bloquea la base de datos del servicio.
QueryLock Consulta el LockStatus de la base de datos SCM

Opciones de Query y QueryEx en caso de que la consulta vaya seguida de un nombre de servicio, se devolverá el estado del mismo y no se aplican más opciones. Si la consulta no va seguida de nada o de una de las opciones siguientes, se enumerarán los servicios.    

type= Tipo de servicios que se enumerar n (controlador, servicio, todos)(valor predeterminado = servicio)
state= Estado de los servicios que se enumeran (inactivo, todos)(valor predeterminado = activo)
bufsize= Tamaño (en bytes) del búfer de enumeración (valor predeterminado = 4096)
ri= El número de índice de reanudación en el que comenzar la enumeración (valor predeterminado = 0)
group= Grupo de servicio que se enumerar (valor predeterminado = todos los grupos)

Ejemplos de sintaxis:

sc query

– Enumera el estado de controladores y servicios activos

sc query eventlog

– Muestra el estado del servicio de registro de eventos

sc queryex eventlog

– Muestra el estado extendido del servicio de registro de eventos

sc query type= driver

– Enumera sólo los controladores activos

sc query type= service

– Enumera sólo los servicios de Win32

sc query state= all

– Enumera todos los servicios y controladores

sc query bufsize= 50

– Enumera con un búfer de 50 bytes

sc query ri= 14

– Enumera con índice de reanudación = 14

sc queryex group= «»

– Enumera los servicios activos que no están en un grupo

sc query type= interact

– Enumera todos los servicios interactivos

sc query type= driver group= NDIS

– Enumera todos los controladores NDIS

 ERRORES DE INICIO DEL SERVICIO

Estos errores se producen cuando SCM carga un servicio durante el inicio del sistema. Algunos mensajes comunes de error de inicio:

ERROR_SERVICE_ALREADY_RUNNING

ERROR_SERVICE_DEPENDENCY_FAIL

Cuando un controlador o servicio devuelve un error en respuesta al comando de inicio del SCM, el valor de la entrada ErrorControl en el registro determina la reacción del SCM.

  • Si el valor es 0 o no está especificado, SCM ignora el error y sigue procesando el inicio del servicio.
  • Si el valor es 1, SCM registra un evento en el registro de sucesos del sistema, que dice, «El Servicio <nombre_servicio> ha fallado en su inicio debido al siguiente error:» y sigue procesando el inicio del servicio. SCM incluye la representación en texto del código de error de Win32 que el servicio ha devuelto al SCM como la razón de su fallo de inicio en el registro del suceso grabado.
  • Si el valor es 2 o 3, SCM registra un evento en el registro de sucesos y cambia la configuración del registro de la última configuración buena conocida, con la que el equipo inicio correctamente la última vez. Y entonces reinicia el equipo usando la función shutdown, que está implementada en la parte ejecutiva del kernel. Si el equipo ya está en ejecución con la última configuración buena conocida, simplemente se reinicia.

Detectar servicios que no responden

Determinar si un servicio está detenido o colgado puede ser a veces difícil. Si un servicio deja de responder en cualquier estado a excepción de SERVICE_STOPPED, el complemento Services y Net.exe informarán que sigue en ejecución. Por ejemplo, si un servicio deja de responder cuando se encuentra en el estado SERVICE_STOP_PENDING, el comando Net start informará que su estado es ejecutándose y el complemento Servicios indicará que se encuentra detenido. Una comparación de como informan del estado las herramientas:

Estado

Services

Net.exe

Sc.exe

SERVICE_STOP_PENDING SERVICE_RUNNING SERVICE_RUNNING SERVICE_STOP_PENDING
SERVICE_START_PENDING SERVICE_RUNNING SERVICE_RUNNING SERVICE_START_PENDING

Si intentamos iniciar un servicio detenido con el estado SERVICE_STOP_PENDING o SERVICE_START_PENDING, Net.exe indicará que el servicio ya está en ejecución.

La forma de conocer los servicios que no se están ejecutando en un equipo es usando el comando:

sc query type= service state= inactive

Y si queremos consultar un servicio en concreto:

sc query service nombre_servicio

Los servicios tienen tendencia a colgarse cuando están en estado SERVICE_START_PENDING. También en el estado SERVICE_STOP_PENDING si hay problemas su apagado.

Algunas veces pueden aparecer como colgados porque SCM está esperando a que un servicio cambie de estado. SCM espera a que un servicio se inicie en dos casos:

  • El servicio se está iniciando automáticamente.
  • El servicio está siendo iniciado por SCM ya que se llamo a StartService por un servicio que depende de él.

En ambos casos, SCM espera 80 segundos extra para que el servicio cambie su estado de SERVICE_START_PENDING o para llamar a SetServiceStatus otra vez con un punto de comprobación nuevo.

Si el servicio tarda demasiado en iniciarse, supera el tiempo total de espera de SCM, éste lo marcará como fallado (colgado en el inicio), registrará un suceso, EVENT_SERVICE_START_HUNG, y sigue adelante. Este evento se registra sólo si el nivel de error del servicio no se ignora. Si se ignora, podremos ver el mensaje la próxima vez que Windows se inicie. Ya que SCM no detiene un servicio colgado, podemos utilizar sc.exe para ver cuales servicios permanecen en un estado SERVICE_START_PENDING y de ellos cuales no responden.

Si el servicio llama a SetServiceStatus en algún momento durante este intervalo y especifica un nuevo punto de comprobación, SCM reiniciará su tiempo de espera. Un nuevo punto de comprobación le indica a SCM que sigue pendiente pero que ha realizado algún progreso.

El tiempo de espera puede detectarse mediante el campo dwWaitHint de la estructura SERVICE_STATUS que se pasa. Podemos comprobar este valor mediante el comando sc query servicio, donde servicio es el que no responde (el tiempo de espera es válido sólo cuando el servicio está en el estado SERVICE_START_PENDING).

Más herramientas: psexec.exe

Desde que conocí a Mark Russinovich, además de oírle en sus presentaciones en diversos Tech-Ed’s en Barcelona, en una fiesta en el último Tech-Ed en el Elephant Club de BCN, se me acrecentó la ya admiración que sentia por este gurú.

Las sysinternals, producto suyo, son unas herramientas valiosas, hoy os muestro una sencilla manera de ejecutar una ventana cmd (entre otras posibilidades) en un equipo remoto, vamos, sin tener que desplazarnos al lugar ni siquiera usar Terminal Services o cualquier herramienta de escritorio remoto y ejecutar los comandos tan fácilmente como estar frente al equipo.

La forma más corriente de conectar y abrir la cmd en el equipo remoto desde el nuestro es:

psexec \Equipo -u Usuario cmd

psexec01

Inicio desde mi Vista una ventana de comandos, una vez en el directorio de las herramientas, ejecuto el comando. Se inicia, me pide contraseña del usuario utilizado y se la escribo, inicia la conexión el equipo remoto.

psexec02 

Se ha conectado y mira por donde, me muestra un directorio distinto al que yo me encontraba en mi equipo, C:WINDOWSsystem32 pero del equipo remoto.

psexec03

Realizo pequeñas cosas, un ipconfig que me devuelve los datos de la máquina remota a la que me conecté, consulto si hay alguien con sesión iniciada, y efectivamente en la consola se encuentra Juansa, y finalmente salgo con Exit, lo que me devuelve a mi cmd original y en mi directorio de herramientas.

Deberíais profundizar en estas pequeñas cosas, 😉

Queremos el resultado de un script por email

Bien, pues aquí tenemos un script que podemos lanzar para que nos informe del estado de los servicios por email diariamente.

   1: 'Este script sirve para comprobar cambios de estado de los servicios
   2: ' usando event log y enviar después un aviso por email
   3:  
   4: '(c) Juansa 03-12-2008
   5: 'leer el archivo
   6: Function leearchivo (nombreArchivo)
   7:     Const ForReading = 1, ForWriting = 2
   8:        Dim fso, f
   9:        Set fso = CreateObject("Scripting.FileSystemObject")
  10:     Set f = fso.OpenTextFile(nombreArchivo, ForReading)
  11:     leearchivo = f.ReadAll
  12: End Function
  13: 'existe el archivo
  14: Function Existe(archivo)
  15:    Dim fso
  16:    Set fso = CreateObject("Scripting.FileSystemObject")
  17:    If (fso.FileExists(archivo)) Then 
  18:     Existe = True
  19:    Else
  20:       Existe = False
  21:    End If
  22:    
  23: End Function
  24: 'cuerpo script
  25: 'Creamos constantes y variables
  26: Const ForReading = 1, ForWriting = 2
  27: Dim TabStop, NewLine, filename, strDate, dia, mes, ano
  28: TabStop = Chr(9)
  29: NewLine = Chr(10)
  30: dia = left(Date, 2)
  31: ano = right(Date, 4)
  32: mes = mid(Date, 4,2)
  33: strDate = dia & "-" & mes & "-" & ano
  34: filename = "c:scriptsInformeServicios_" & strDate & ".txt"
  35:  
  36: 'comprobaremos que el informe no exista ya
  37: if Existe(filename) = true then
  38: 'no se ejecutará nada
  39: else
  40: Dim fso, miarchivo
  41: Set fso = CreateObject("Scripting.FileSystemObject")
  42: set miarchivo = fso.CreateTextFile(filename, True)
  43: miarchivo.close
  44: Set objFSO = CreateObject("Scripting.FileSystemObject")
  45: Set objFile = objFSO.OpenTextFile(filename, ForWriting, True)
  46:  
  47: Set dtmConvertedDate = CreateObject("wbemScripting.SwbemDateTime")
  48:  
  49: StrComputer = "."
  50: Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=Impersonate}!\" & strComputer &  "rootcimv2")
  51:  
  52: Set ColServiceEvents = objWMIService.ExecQuery ("SELECT * FROM Win32_NTLogEvent WHERE LogFile =  'System' AND " & "EventCode = '7036'")
  53:  
  54: For Each strEvent in ColServiceEvents
  55:     dtmConvertedDate.Value = strEvent.TimeWritten
  56:     objFile.WriteLine dtmConvertedDate.GetVarDate
  57:     objFile.WriteLine strEvent.Message
  58: Next
  59:  
  60:  
  61: 'el archivo se ha creado ya
  62: 'vamos a enviar el email
  63: 'OJO CON LOS DATOS A RELLENAR
  64: esquema = "http://schemas.microsoft.com/cdo/configuration/"
  65: Set cdoConfig = CreateObject("CDO.Configuration")
  66:     With cdoConfig.Fields 
  67:         .Item(esquema & "sendusing") = 2 
  68:         .Item(esquema & "smtpserver") = "tuservidorSMTP" 
  69:         .Item(esquema & "smtpauthenticate") = 1 
  70:         .Item(esquema & "sendusername") = "TuUsuario"
  71:         .Item(esquema & "sendpassword") = "Tuclave"
  72:         .Item(esquema & "smtpserverport") = 25 'si se usa otro
  73:         .Item(esquema & "smtpusessl") = False 'si se usa ssl True
  74:         .Item(esquema & "smtpconnectiontimeout") = 60
  75:         .update
  76:     End With
  77: Set cdoMessage = CreateObject("CDO.Message")
  78:     With cdoMessage
  79:         Set .Configuration = cdoConfig
  80:         .From = "tucuenta@tudominio"
  81:         .To = "tucuenta@tudominio"
  82:         .Subject = "prueba de envío"
  83:         .TextBody = "El equipo ha tenido un error, revisa el registro"
  84:         .Send
  85:     End With
  86: Set cdoMessage = Nothing
  87: Set cdoConfig = Nothing
  88: end if
  89: ' wscript.Echo "FINAL"

Cualquier otro script puede montarse de la misma manera, así como asignar el envío de un correo a un eventtrigger por ejemplo.

Monitorizar los Servicios, y 4

Monitorizar el rendimiento del servicio


Hemos monitorizado los servicios en cuanto a su disponibilidad y su fiabilidad, pero nos falta algo, ¿podemos llevar a cabo alguna monitorización que nos ayude a impedir los fallos?.


Una estrategia de monitorización que nos ayude a hacer lo siguiente:



  • Determinar porqué se ha detenido el servicio. ¿Se queda sin memoria?, ¿Demasiados usuarios accediendo? ¿Algún cuello de botella en los discos o la red?
  • Predecir los fallos con antelación. Con ciertos servicios puede que seamos capaces de predecir su fallo si el servicio excede de un umbral específico. Aquí podemos servirnos de un script que monitorice las operaciones por segundo que realiza el servicio. Cuando el valor se aproxime al umbral específico, el script puede o limitar el número de conexiones simultáneas o encaminar a los usuarios hacia otros servicios iguales en otros equipos.

¿Cómo podríamos monitorizar el rendimiento?



  • Monitorizar el proceso del servicio. Cada servicio tiene un proceso responsable del mismo. Si lo monitorizamos podemos asegurarnos que utiliza la memoria y otros recursos adecuadamente. Sin embargo no podemos saber si el servicio está llevando a cabo su función eficientemente. El servicio podría tener un montón de memoria disponible, simplemente porque ya no responde solicitudes de los usuarios.
  • Llevar a cabo un test estándar. Para algunos servicios, podemos realizar un test y entonces medir el tiempo de respuesta del servicio. Comparando el tiempo de respuesta con el tiempo que tenemos como base podemos hacernos una idea sobre si el servicio está dentro del los límites esperados.
  • Monitorizar el rendimiento mediante el uso de contadores. Los contadores representan la mejor forma de monitorizar el rendimiento actual de un servicio.

Los contadores de rendimiento están incluidos para muchos servicios en Windows Server 2003 y Windows XP Professional, como DHCP, DNS, WINS y IIS. Sin embargo, muchos de los servicios, especialmente los que no vienen con el propio sistema operativo, no incluyen contadores de rendimiento. Esto significa que no seremos capaces de usar contadores de rendimientos para monitorización de todos los servicios en nuestra red.


Para realizar la monitorización podemos utilizar scripts de Shell (TypePerf.exe y Logman.exe) o de WMI (Win32_PerfFormattedData), pero aún así, los contadores pueden usarse desde el monitor de rendimiento, tanto en tiempo real como ir guardando los datos en un archivo.


Un Script para el servicio Web:



   1:  
   2: StrComputer = «.»
   3: Set objWMIService = GetObject(«winmgmts:» & «{impersonationLevel=Impersonate}!\» & strComputer & «rootcimv2»)
   4: Set objRefresher = CreateObject(«wbemscripting.SWbemRefresher»)
   5: Set ColW3SVC = objRefresher.AddEnum (objWMIService, «win32_PerfFormattedData_W3SVC_WebService»).ObjectSet
   6: objRefresher.Refresh
   7: For i = 1 to 60
   8:   For each objW3SVC in ColW3SVC
   9:     Wscript.Echo «Conexiones  en  este momento: « & objW3SVC.CurrentConnections & _
  10:     VbCrLf & «Usuarios anónimos    por segundo: « & objW3SVC.AnonymousUsersPerSec & _
  11:     VbCrLf & «Intentos de conexión por segundo: « & objW3SVC.ConnectionAttemptsPerSec & _
  12:     VbCrLf & «Usuarios anónimos     conectados: « & objW3SVC.CurrentAnonymousUsers & _
  13:     VbCrLf & «Archivos servidos    por segundo: « & objW3SVC.FilesPerSec & _
  14:     VbCrLf & «Conexiones  máximas simultáneas : « & objW3SVC.MaximumConnections
  15:   Next
  16: wscript.Sleep 1000
  17: objRefresher.Refresh
  18: Next

 


Como hago lo mismo con el monitor de rendimiento:



  1. Abro el complemento Rendimiento.
    monitorizaciónrendimiento01 
  2. Quito los contadores por defecto.
    monitorizaciónrendimiento02 monitorizaciónrendimiento03
  3. Añado los que quiero y del servicio que quiero, en este caso Web Service.
    monitorizaciónrendimiento04 monitorizaciónrendimiento05
  4. El monitor muestra información. En concreto, una línea indica el máximo de conexiones permitidas (le he indicado al servicio web sólo 2) y los usuarios anónimos conectados, he conectado desde otro equipo dos ventanas de IE al mismo servicio(2) y es lo que indica.
    monitorizaciónrendimiento06

Monitorizar los Servicios 3

 


Monitorizar los cambios en el estado de los servicios mediante Registro de Sucesos


Los cambios en el estado de los servicios no se registraban en en el registro de sistema en versiones de Windows anteriores a Windows Server 2003 y Windows XP. En su lugar, un evento relacionado con un servicio sólo se registraba cuando el servicio fallaba. Esto no ayuda a monitorizar los servicios y su rendimiento en toda la red. Aunque una herramienta de monitorización puede descubrir si un servicio ha sido detenido, no podemos saber quién lo hizo, cuando ni porqué. Por ello, desconocemos si otro administrador o usuario avanzado ha detenido el servicio intencionadamente, o si se ha detenido por un problema de hardware o software.


En Windows Server 2003 y Windows XP professional, sin embargo, los sucesos se registran automáticamente en el registro de sistema siempre que se produzca un cambio en el estado del servicio, o siempre que un código de control se le envió al servicio. Por ejemplo, cuando un servicio cambia de estado, un suceso 7036 se registra:


evento7036


Este es el evento provocado por la detención del servicio BITS que realicé manualmente para que el script del artículo anterior detectase y guardase en un archivo el cambio de estado de un servicio.


Asimismo, un evento 7035 se grabará cada vez que un código de control sea enviado al servicio.


Ya que podemos usar WMI para recuperar eventos seleccionados desde el registro de sucesos, podemos seguir la fiabilidad del servicio periódicamente consultando al registro de sucesos y anotando las fechas y horas en que los servicios se detienen o inician.



   1: ‘Este script sirve para comprobar cambios de estado de los servicios
   2: ‘ usando event log y anotándolo en un archivo de texto
   3:  
   4: ‘(c) Juansa 29-11-2008
   5:  
   6:  
   7:  
   8: Const ForReading = 1, ForWriting = 2
   9: Dim TabStop, NewLine
  10: TabStop = Chr(9)
  11: NewLine = Chr(10)
  12: Set objFSO = CreateObject(«Scripting.FileSystemObject»)
  13: Set objFile = objFSO.OpenTextFile(«C:scriptsServicios_cambios.txt», ForWriting, True)
  14:  
  15: Set dtmConvertedDate = CreateObject(«wbemScripting.SwbemDateTime»)
  16:  
  17: StrComputer = «.»
  18: Set objWMIService = GetObject(«winmgmts:» & «{impersonationLevel=Impersonate}!\» & strComputer &  «rootcimv2»)
  19:  
  20: Set ColServiceEvents = objWMIService.ExecQuery («SELECT * FROM Win32_NTLogEvent WHERE LogFile =  ‘System’ AND « & «EventCode = ‘7036’»)
  21:  
  22: For Each strEvent in ColServiceEvents
  23:     dtmConvertedDate.Value = strEvent.TimeWritten
  24:     objFile.WriteLine dtmConvertedDate.GetVarDate
  25:     objFile.WriteLine strEvent.Message
  26: Next

 


Cuyo resultado nos da:


eventQuery