9 Motor Database
El motor Database obtiene los datos ejecutando sentencias SQL sobre una base de datos. Es el motor por defecto: un monitor sin General.Engine usa este motor.
9.1 Configuración: sección [Database]#
| Parámetro | Descripción |
|---|---|
DBDriver |
Obligatorio. Driver: Oracle, PGsql u ODBC. |
ConnectionString |
Obligatorio. Cadena de conexión. Su formato depende del driver (sección 9.2). |
UserName |
Obligatorio. Usuario de la base de datos. |
Password |
Obligatorio. Contraseña. |
ConnectOptions |
Opciones especiales. La única admitida es SYSDBA (necesaria para ASM). |
El usuario de base de datos solo necesita permisos de lectura sobre las vistas que consultan los XML.
9.2 Drivers#
El parámetro DBDriver elige el driver con el que se conecta el monitor. Cada driver interpreta a su manera la cadena de conexión, admite unos contextos concretos y ofrece unos datos de ejecución propios.
| DBDriver | Bases de datos | Contextos | Cadena de conexión |
|---|---|---|---|
Oracle |
Oracle (OCI) | Container |
Alias de tnsnames.ora, Easy Connect o descriptor completo. |
PGsql |
PostgreSQL (libpq) | Database |
Pares clave=valor de libpq. |
ODBC |
Cualquiera con driver ODBC (SQL Server, DB2/400…) | Database |
Cadena de SQLDriverConnect: DSN=nombre o DRIVER={…};… |
Nota. PostgreSQL y Oracle también se pueden usar a través del driver ODBC, con un driver ODBC del fabricante o de terceros. Aun así, se recomienda usar el driver nativo (PGsql u Oracle) siempre que sea posible: es el que conoce los contextos de cada base de datos (Database en PostgreSQL, Container en Oracle) y el que ofrece sus datos de ejecución específicos, como ORACLE.CONTAINER.
En todos los drivers, las variables de enlace de las consultas BIND se escriben siempre con la forma :nombre. El driver las convierte a la sintaxis de cada base de datos ($1, $2… en PostgreSQL, ? en ODBC).
9.2.1 Driver Oracle#
- Cadena de conexión.
-
Se pasa tal cual al cliente de Oracle, así que admite cualquier forma que este acepte:
ConnectionString = oraprod # alias de tnsnames.ora ConnectionString = dbhost.empresa.com:1521/ORAPROD # Easy Connect ConnectionString = (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dbhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORAPROD)))Para usar alias, la variable
TNS_ADMINdel servicio debe apuntar al directorio deltnsnames.ora. - ConnectOptions.
-
SYSDBAconecta con privilegios de administrador (necesario para ASM). Sin valor, conexión normal. - Contextos.
-
Container: el contenedor (PDB) activo, que se cambia conALTER SESSION SET CONTAINER. Solo está disponible en Oracle 12c o posterior, en una base de datos multitenant y conectando al contenedor raíz (CDB$ROOT). En cualquier otro caso, el driver no admite contextos yORACLE.CONTAINERvale0. - Variables de enlace.
-
Nativas de Oracle (
:nombre).
9.2.2 Driver PGsql#
- Cadena de conexión.
-
Pares
clave=valorde libpq separados por espacios (host,port,dbname,sslmode,connect_timeout…). El usuario y la contraseña se añaden desdeUserNameyPassword; no los ponga en la cadena.ConnectionString = host=pg01.empresa.com port=5432 dbname=postgres sslmode=require - ConnectOptions.
-
No se usa.
- Contextos.
-
Database: la base de datos activa. Como PostgreSQL no permite cambiar de base de datos en una conexión, el driver abre una conexión por cada base de datos que se usa (sustituyendo eldbnamede la cadena) y las mantiene abiertas. - Variables de enlace.
-
Se convierten a
$1,$2…
Atención. Incluya siempre dbname en la cadena de conexión: el driver lo usa como base de datos por defecto y lo sustituye al cambiar de contexto. La contraseña se añade a la cadena sin comillas, así que no puede contener espacios.
9.2.3 Driver ODBC#
- Cadena de conexión.
-
Se pasa a
SQLDriverConnectañadiendo;UID=…;PWD=…con el usuario y la contraseña. Puede referirse a una fuente de datos deodbc.inio describir la conexión completa:ConnectionString = DSN=MSSQL_PROD ConnectionString = DRIVER={FreeTDS};SERVER=mssql.empresa.com;PORT=1433;DATABASE=masterPara usar
DSN, la variableODBCINIdel servicio debe apuntar al ficheroodbc.ini. - ConnectOptions.
-
No se usa.
- Contextos.
-
Database: la base de datos (catálogo) activa, que se cambia en la misma conexión con el atributo ODBCSQL_ATTR_CURRENT_CATALOG. Funciona con los drivers que lo admiten, como los de SQL Server. - Variables de enlace.
-
Se convierten a
?.
Nota. La contraseña se añade a la cadena sin comillas, así que no puede contener el carácter ;.
9.2.4 Datos de ejecución#
Los datos de ejecución se consultan en las condiciones de <when> con runtime(’NOMBRE’) (sección 9.6) y en queryexplorer con getRuntimeValue.
| Nombre | Driver | Valor |
|---|---|---|
DATABBIX.PROGRAM_NAME |
todos | databbix, o queryexplorer en esa utilidad. |
CONN.TYPE |
todos | Database. |
DB.DRIVER |
Oracle | Oracle. |
| PGsql | PostgreSQL. |
|
| ODBC | ODBC. |
|
DB.DATABASE |
Oracle | Oracle. |
| PGsql | PostgreSQL. |
|
| ODBC | Nombre del producto que informa el driver ODBC (SQL_DBMS_NAME): por ejemplo, Microsoft SQL Server o DB2/400 SQL. |
|
DB.VERSION |
Oracle | Versión del servidor, con la forma mayor.menor.actualización. |
| PGsql | Parámetro server_version del servidor, por ejemplo 15.4. |
|
| ODBC | Versión que informa el driver ODBC (SQL_DBMS_VER). |
|
ORACLE.CONTAINER |
Oracle | 1 si el contexto Container está disponible; 0 si no. |
Así, un mismo XML puede elegir el SQL según el producto (runtime(’DB.DATABASE’) = ’Microsoft SQL Server’), según la versión (major(runtime(’DB.VERSION’)) >= 12) o según si la base de datos es multitenant (runtime(’ORACLE.CONTAINER’) = ’1’).
9.3 Consultas SQL: elementos propios del motor#
Además de los elementos comunes (capítulo 7), las consultas del motor Database usan:
| Elemento / atributo | Descripción |
|---|---|
<sql> |
Texto de la sentencia. Obligatorio salvo en las consultas constantes. Admite variables ${…} y alternativas con <multiple> (sección 9.6). |
<sql context="C"> |
Solo en descubrimientos: sentencia que devuelve los valores del contexto C que hay que recorrer (sección 9.4.4). |
select |
Atributo de <query>: FILTER o BIND. Sin él, la consulta es básica. |
<item column="…"> |
Columna del resultado de la que sale el valor. No distingue mayúsculas de minúsculas. |
<parameter column> |
En consultas FILTER: columna que se compara con el parámetro. |
<parameter bind> |
En consultas BIND: variable de enlace del SQL. |
<parameter context> |
Contexto en el que se ejecuta la consulta. |
<default> |
Contexto fijo de la consulta (sección 9.5). |
<field column|context> |
En descubrimientos: de dónde sale el valor de la macro. |
<context> |
En <Queries>: declaración de un contexto. |
Nota. Conviene dar siempre un alias explícito (as nombre) a las columnas calculadas, y usar esos alias en column.
9.4 Tipos de consulta#
Los ejemplos de esta sección muestran, para cada tipo, el resultado de la sentencia SQL en un momento dado y el valor que obtiene cada clave de Zabbix a partir de él.
9.4.1 Consulta básica#
La sentencia devuelve exactamente una fila. Cada <item> toma el valor de una columna.
<query name="PGWriter" module="PG">
<sql><![CDATA[
select checkpoints_timed, checkpoints_req from pg_stat_bgwriter
]]>
</sql>
<item name="tez.pg.checkpointtimed" column="checkpoints_timed"/>
<item name="tez.pg.checkpointreq" column="checkpoints_req"/>
</query>Resultado de la sentencia
| checkpoints_timed | checkpoints_req |
|---|---|
| 1842 | 37 |
Valores obtenidos
| Clave | Valor |
|---|---|
| tez.pg.checkpointtimed | 1842 |
| tez.pg.checkpointreq | 37 |
Si la sentencia devuelve cero filas o más de una, todos los ítems de la consulta pasan a no soportados.
9.4.2 Consulta de filtro (select="FILTER")#
La sentencia devuelve muchas filas. Cada <parameter> con column relaciona un parámetro de la clave con una columna, y cada ítem se queda con la fila cuyas columnas coinciden con los parámetros de su clave. La sentencia se ejecuta una sola vez para todos los ítems, así que es la forma más eficiente de vigilar colecciones de objetos (tablespaces, bases de datos, trabajos…).
<query name="PGSessions" module="PG" select="FILTER">
<sql><![CDATA[
select datname,
count(st.pid) as n,
sum(case st.state when 'active' then 1 else 0 end) as active
from pg_database db
left outer join pg_stat_activity st using (datname)
where datname not like 'template%'
group by datname
]]>
</sql>
<parameter column="datname" order="1" type="STRING"/>
<item name="tez.pg.sessions" column="n"/>
<item name="tez.pg.sessionsactive" column="active" default="0"/>
</query>Resultado de la sentencia
| datname | n | active |
|---|---|---|
| postgres | 3 | 1 |
| ventas | 12 | 4 |
| rrhh | 0 | 0 |
Valores obtenidos
| Clave | Fila elegida | Valor |
|---|---|---|
| tez.pg.sessions[ventas] | ventas | 12 |
| tez.pg.sessionsactive[ventas] | ventas | 4 |
| tez.pg.sessions[rrhh] | rrhh | 0 |
| tez.pg.sessions[compras] | ninguna | no soportado |
| tez.pg.sessionsactive[compras] | ninguna | 0 (atributo default) |
| tez.pg.sessions[Ventas] | ninguna | no soportado |
Las cuatro primeras claves se resuelven con una única ejecución de la sentencia. La comparación es exacta: distingue mayúsculas y minúsculas (Ventas no coincide con ventas) y solo elimina los espacios de los extremos del parámetro. Si una columna tiene espacios de relleno (tipo char), recórtelos en el SQL con trim().
Varias columnas de filtro#
Con varios parámetros de filtro, la clave lleva un parámetro por cada uno, en el orden que indica order, y la fila tiene que coincidir en todos:
<query name="MSStateRepl" module="MSSQL" select="FILTER">
<sql><![CDATA[ exec sp_replmonitorhelppublication ]]></sql>
<default context="Database" value="distribution"/>
<parameter column="publisher_db" order="1" type="STRING"/>
<parameter column="publication" order="2" type="STRING"/>
<item name="tez.mssql.repl.status" column="status"/>
</query>Resultado de la sentencia
| publisher_db | publication | status |
|---|---|---|
| ventas | pub_pedidos | 3 |
| ventas | pub_clientes | 2 |
| compras | pub_pedidos | 6 |
Valores obtenidos
| Clave | Valor |
|---|---|
| tez.mssql.repl.status[ventas,pub_pedidos] | 3 |
| tez.mssql.repl.status[compras,pub_pedidos] | 6 |
| tez.mssql.repl.status[ventas] | no soportado (falta un parámetro) |
Parámetros numéricos#
Con type="INT", el parámetro y la columna se comparan como números. Así, la clave no tiene que reproducir el formato exacto de la columna:
<parameter column="job_id" order="1" type="INT"/>
<item name="local.job.status" column="status"/>Resultado de la sentencia y valores obtenidos
| job_id | status | Clave | Valor |
|---|---|---|---|
| 7 | OK | local.job.status[7] | OK |
| 42 | ERROR | local.job.status[042] | ERROR |
Con type="STRING", la clave local.job.status[042] no encontraría la fila, porque el texto 042 es distinto de 42.
9.4.3 Consulta con variables de enlace (select="BIND")#
El parámetro de la clave se pasa a la sentencia como variable de enlace. La sentencia se ejecuta una vez por cada clave distinta y debe devolver exactamente una fila.
<query name="PGParameter" module="PG" select="BIND">
<sql><![CDATA[
select setting from pg_settings where name = :name
]]>
</sql>
<parameter bind=":name" order="1" type="STRING"/>
<item name="tez.pg.param" column="setting"/>
</query>Ejecuciones y valores obtenidos
| Clave | Valor de :name | Valor |
|---|---|---|
| tez.pg.param[max_connections] | ’max_connections’ | 200 |
| tez.pg.param[work_mem] | ’work_mem’ | 4096 |
| tez.pg.param[no_existe] | ’no_existe’ | no soportado (0 filas) |
La variable se escribe siempre como :nombre, sea cual sea el driver (sección 9.2). Con type="INT", el valor se enlaza como número.
Atención. Como se ejecuta una vez por clave, una consulta BIND es mucho más costosa que una FILTER cuando hay muchas claves. Úsela solo cuando el conjunto de valores posibles sea muy grande y se consulten pocos.
9.4.4 Consulta de descubrimiento#
Cada fila del resultado es una entidad descubierta, y cada <field> toma el valor de una columna (column) o de un contexto (context).
<query name="TSDiscover" module="DB" discovery="yes">
<sql><![CDATA[
select tablespace_name, contents
from dba_tablespaces where status = 'ONLINE'
]]>
</sql>
<item name="tez.ora.tspace.discovery"/>
<field name="TSNAME" column="tablespace_name"/>
<field name="CONTENTS" column="contents"/>
</query>Resultado de la sentencia
| tablespace_name | contents |
|---|---|
| SYSTEM | PERMANENT |
| USERS | PERMANENT |
| TEMP | TEMPORARY |
Valor del ítem tez.ora.tspace.discovery:
{"data":[
{"{#TSNAME}":"SYSTEM", "{#CONTENTS}":"PERMANENT"},
{"{#TSNAME}":"USERS", "{#CONTENTS}":"PERMANENT"},
{"{#TSNAME}":"TEMP", "{#CONTENTS}":"TEMPORARY"}
]}
En Zabbix, el prototipo tez.ora.tspace.pctfree[{#TSNAME}] genera los ítems tez.ora.tspace.pctfree[SYSTEM], [USERS] y [TEMP], que resuelve una consulta FILTER con parameter column="tablespace_name".
Los descubrimientos solo admiten parámetros de contexto.
Descubrimiento a través de contextos#
Un descubrimiento puede recorrer todos los valores de un contexto: por ejemplo, listar los filegroups de todas las bases de datos de un SQL Server. Para ello se añade un <sql> con atributo context que devuelve, en su primera columna, los valores que hay que recorrer. La sentencia principal se ejecuta una vez en cada uno:
<query name="MSDiscoverFG" module="MSSQL" discovery="yes">
<sql context="Database"><![CDATA[
select name from sys.databases where name not in ('model')
]]>
</sql>
<sql><![CDATA[
select name from sys.filegroups
]]>
</sql>
<item name="tez.mssql.fg.discovery"/>
<field name="DBNAME" context="Database"/>
<field name="FGNAME" column="name"/>
</query>Resultado de las sentencias
| Sentencia de contexto | Sentencia principal en cada base de datos | |
| name | base de datos | name |
| master | master | PRIMARY |
| ventas | ventas | PRIMARY |
| ventas | HISTORICO | |
Valor del ítem tez.mssql.fg.discovery:
{"data":[
{"{#DBNAME}":"master", "{#FGNAME}":"PRIMARY"},
{"{#DBNAME}":"ventas", "{#FGNAME}":"PRIMARY"},
{"{#DBNAME}":"ventas", "{#FGNAME}":"HISTORICO"}
]}
Los valores de contexto en los que no se puede entrar (por ejemplo, una base de datos fuera de línea) se saltan y quedan registrados en el log.
9.5 Contextos#
Un contexto es un estado de la conexión que se puede cambiar entre consultas, como la base de datos activa en SQL Server o PostgreSQL o el contenedor (PDB) en Oracle multitenant. Así, un único monitor con una sola conexión puede consultar varias bases de datos de un mismo servidor. Los contextos solo existen en el motor Database.
9.5.1 Declaración#
Los contextos se declaran en el nivel de <Queries>:
<environment name="PGAdminDB" default="postgres"/>
<context name="Database" module="PG" default="${PGAdminDB}"/>| Atributo | Descripción |
|---|---|
name |
Obligatorio. Nombre del contexto. El driver debe saber cambiarlo; los nombres habituales son Database (SQL Server, PostgreSQL) y Container (Oracle multitenant). |
module |
Obligatorio. Módulo al que pertenece. |
default |
Obligatorio. Valor por defecto. Admite variables ${…}. |
9.5.2 Uso en consultas#
Hay tres formas de elegir el contexto de una consulta:
Por defecto. Si la consulta no dice nada, se ejecuta con el valor
defaultdel contexto.Fijo para la consulta, con
<default>:<default context="Database" value="msdb"/>Si
valuevale__IGNORE__(por ejemplo, a través de una variable de entorno sin configurar), el elemento se ignora y se mantiene el valor por defecto.Tomado de la clave del ítem, con un parámetro de contexto:
<parameter context="Database" order="1"/>
9.5.3 Ejemplo: filtro dentro de cada base de datos#
Con un parámetro de contexto, el primer parámetro de la clave elige la base de datos y los siguientes, la fila:
<context name="Database" module="MSSQL" default="master"/>
<query name="MSFGSpace" module="MSSQL" select="FILTER">
<sql><![CDATA[
select g.name as filegroup_name,
sum(cast(fileproperty(f.name, 'SPACEUSED') as bigint) * 8192) as used
from sys.database_files f
inner join sys.filegroups g on g.data_space_id = f.data_space_id
group by g.name
]]>
</sql>
<parameter context="Database" order="1"/>
<parameter column="filegroup_name" order="2" type="STRING"/>
<item name="tez.mssql.fgspace.used" column="used"/>
</query>Resultado de la sentencia en cada base de datos
| base de datos | filegroup_name | used |
|---|---|---|
| master | PRIMARY | 5242880 |
| ventas | PRIMARY | 73400320 |
| ventas | HISTORICO | 524288000 |
Valores obtenidos
| Clave | Contexto | Valor |
|---|---|---|
| tez.mssql.fgspace.used[ventas,HISTORICO] | ventas | 524288000 |
| tez.mssql.fgspace.used[ventas,PRIMARY] | ventas | 73400320 |
| tez.mssql.fgspace.used[master,PRIMARY] | master | 5242880 |
Databbix agrupa las ejecuciones por contexto: entra en ventas una sola vez, ejecuta la sentencia y resuelve las dos primeras claves con el mismo resultado. Si no puede entrar en un contexto, marca como no soportados los ítems de ese contexto. Si el contexto que falla es el por defecto y ConnLostOnDefaultCtxError = yes, da la conexión por perdida y reconecta.
9.6 SQL alternativo según la base de datos#
Un mismo XML puede servir para distintos productos o versiones de base de datos si el texto SQL se elige al ejecutar, con <multiple>:
<sql>
<multiple>
<when condition="runtime('DB.DATABASE') = 'Oracle'"><![CDATA[
select count(*) as n from ${SvmSchema}.f986110
where trim(jcfndfuf2) = :jobname
]]>
</when>
<when condition="runtime('DB.DATABASE') = 'Microsoft SQL Server'"><![CDATA[
select count(*) as n from ${SvmSchema}.f986110
where rtrim(jcfndfuf2) = :jobname
]]>
</when>
<when><![CDATA[
-- sin condición: se usa si ninguna anterior se cumple
select count(*) as n from ${SvmSchema}.f986110
where jcfndfuf2 = :jobname
]]>
</when>
</multiple>
</sql>Se usa el primer <when> cuya condición se cumple. Un <when> sin condición se cumple siempre, así que debe ir el último. Si no se cumple ninguna condición, la consulta falla.
Las condiciones son expresiones que pueden usar estas funciones:
| Función | Descripción |
|---|---|
runtime(’X’) |
Dato de ejecución de la conexión activa, por ejemplo DB.DATABASE o DB.VERSION (sección 9.2.4). |
environment(’X’) |
Valor de una variable de entorno. |
major(’X.Y.Z’) |
Primer número de una versión, como número. |
toscalar(’X’) |
Convierte un texto en número. |
Admiten operadores de comparación (=, !=, <, >…) y lógicos (and, or, not). Los datos de ejecución disponibles con cada driver se pueden consultar con el comando getRuntimeNames de queryexplorer.
9.7 Ejemplos de configuración#
9.7.1 Ejemplo: Oracle#
[General]
Name = ORAPROD
[Zabbix]
Server = zabbix.empresa.com
Port = 10051
PassivePort = 10153
[Data]
Module = DB
Module = Instance
[Database]
DBDriver = Oracle
ConnectionString = oraprod # alias de tnsnames.ora
UserName = zabbix
Password = secreto9.7.2 Ejemplo: Oracle multitenant#
[General]
Name = ORACDB
QueryFile = /etc/databbix/query-mt.xml
[Zabbix]
Server = zabbix.empresa.com
Port = 10051
[Data]
Module = MT
[Database]
DBDriver = Oracle
ConnectionString = oracdb
UserName = c\043\043zabbix # c##zabbix
Password = secreto9.7.3 Ejemplo: ASM#
[General]
Name = asm
[Zabbix]
Server = zabbix.empresa.com
Port = 10051
[Data]
Module = ASM
[Database]
DBDriver = Oracle
ConnectionString = asm
ConnectOptions = SYSDBA
UserName = sys
Password = secreto9.7.4 Ejemplo: PostgreSQL#
[General]
Name = PGPROD
QueryFile = /etc/databbix/query-pg.xml
QueryFile = /etc/databbix/query-pg-10.xml
Environment = PGAdminDB=postgres
[Zabbix]
Server = zabbix.empresa.com
Port = 10051
[Data]
Module = PG
[Database]
DBDriver = PGsql
ConnectionString = host=pg01.empresa.com port=5432 dbname=postgres
UserName = zabbix
Password = secreto9.7.5 Ejemplo: SQL Server por ODBC#
Primero se define la fuente de datos en /etc/databbix/odbc.ini:
[MSSQL_PROD]
Driver=FreeTDS
Description=SQL Server de producción
Server=mssql.empresa.com
Port=1433
Database=masterY después el monitor la referencia por su nombre:
[General]
Name = MSSQLPROD
QueryFile = /etc/databbix/query-mssql.xml
[Zabbix]
Server = zabbix.empresa.com
Port = 10051
[Data]
Module = MSSQL
[Database]
DBDriver = ODBC
ConnectionString = DSN=MSSQL_PROD
UserName = zabbix
Password = secreto