parseo - python bnf
Implementando un "motor de reglas" en Python (5)
Estoy escribiendo una aplicación de recopilación / análisis de registros en Python y necesito escribir un "motor de reglas" para que coincida y actúe en los mensajes de registro.
Necesita presentar:
- Coincidencia de expresión regular para el mensaje mismo
- Comparaciones aritméticas para la gravedad / prioridad del mensaje
- operadores booleanos
Imagino Una regla de ejemplo probablemente sería algo así como:
(message ~ "program//[/d+//]: message" and severity >= high) or (severity >= critical)
Estoy pensando en usar PyParsing o similar para realmente analizar las reglas y construir el árbol de análisis sintáctico.
El diseño actual (aún no implementado) que tengo en mente es tener clases para cada tipo de regla, y construirlas y encadenarlas de acuerdo con el árbol de análisis sintáctico. Entonces, cada regla tendría un método de "coincidencias" que podría hacer que un objeto de mensaje devuelva si coincide o no con la regla.
Muy rápido, algo así como:
class RegexRule(Rule):
def __init__(self, regex):
self.regex = regex
def match(self, message):
return self.regex.match(message.contents)
class SeverityRule(Rule):
def __init__(self, operator, severity):
self.operator = operator
def match(self, message):
if operator == ">=":
return message.severity >= severity
# more conditions here...
class BooleanAndRule(Rule):
def __init__(self, rule1, rule2):
self.rule1 = rule1
self.rule2 = rule2
def match(self, message):
return self.rule1.match(message) and self.rule2.match(message)
Estas clases de reglas se encadenarían juntas de acuerdo con el árbol de análisis sintáctico del mensaje, y el método match () invocaría la regla superior, que se desplegaría en cascada hasta que se evaluaran todas las reglas.
Me pregunto si este es un enfoque razonable, o si mi diseño e ideas están totalmente fuera de control. Desafortunadamente, nunca tuve la oportunidad de tomar un curso de diseño de compilador ni nada por el estilo en Unviersity, así que estoy preparando esto por mi propia cuenta.
¿Podría alguien con algo de experiencia en este tipo de cosas por favor entrar y evaluar la idea?
EDITAR: Algunas buenas respuestas hasta ahora, aquí hay un poco de aclaración.
El objetivo del programa es recopilar mensajes de registro de servidores en la red y almacenarlos en la base de datos. Además de la recopilación de mensajes de registro, el recopilador definirá un conjunto de reglas que igualará o ignorará los mensajes según las condiciones y marcará una alerta si es necesario.
No puedo ver que las reglas sean más que una complejidad moderada, y se aplicarán en una cadena (lista) hasta que se active una regla coincidente de alerta o ignorar. Sin embargo, esta parte no es tan relevante para la pregunta.
Como la sintaxis está cerca de la sintaxis de Python, sí, eso es cierto, sin embargo, creo que sería difícil filtrar el Python hasta el punto en que el usuario no pudiera hacer inadvertidamente algunas cosas locas con las reglas que no se pretendía.
El único lugar que es diferente de la sintaxis de Python es el message ~ "program//[/d+//]: message"
, por lo que me pregunto si realmente necesita una nueva sintaxis.
Actualización: OK, tiene problemas de usabilidad o seguridad, eso es razonable. Un par de sugerencias:
Tome una sugerencia de Awk y agilice la sintaxis de coincidencia de patrones, por ejemplo,
/program/[/d+/]: message/
lugar demessage ~ "program//[/d+//]: message"
.Lo implementaría traduciendo a una expresión de Python a medida que se analiza la entrada, en lugar de construir un árbol de objetos para evaluar, a menos que espere realizar más operaciones en estas cosas que la evaluación. Esto debería necesitar menos código y correr más rápido. El nivel superior puede ser algo así como:
def compile(input): return eval(''lambda message, severity: %s'' % parse(input))
Otra idea, más allá: escribe tu aplicación en Lua. Está diseñado para que los no programadores amplíen los programas de forma razonablemente segura sin necesidad de aprender mucho. (Se ha utilizado de esa manera con éxito, y se puede evaluar la zona de pruebas para que el código del usuario no pueda acceder a ninguna capacidad que no se le pase explícitamente, según me dijeron).
Me callaré ahora. :-) ¡Buena suerte!
Es un poco difícil responder la pregunta sin saber cuál es el alcance de la aplicación.
- ¿De qué estás tratando de razonar?
- ¿De qué nivel de análisis estás hablando?
- ¿Qué tan complicado ves que se vuelvan las reglas?
- ¿Qué tan complicada es la interacción entre diferentes reglas?
En un extremo del espectro hay un enfoque simple y único como el que propuso. Esto está bien si las reglas son pocas, relativamente simples, y no está haciendo nada más complicado que agregar mensajes de registro que coincidan con las reglas especificadas.
En el otro lado del espectro hay un sistema de razonamiento pesado, algo así como CLIPS que tiene una interfaz de Python . Este es un verdadero motor de reglas con inferencia y ofrece la capacidad de hacer un razonamiento sofisticado. Si está creando algo así como un motor de diagnóstico que opera fuera de un registro de programa, esto podría ser más apropiado.
EDITAR:
Diría que la idea actual de implementación está bien para lo que estás haciendo. Algo más y creo que probablemente corra el riesgo de sobre-diseñar la solución. Parece capturar lo que desea, haciendo coincidir los mensajes de registro con solo unos pocos criterios diferentes.
No invente otro lenguaje de reglas.
Utilice Python o use otro lenguaje existente, ya depurado y en funcionamiento, como BPEL.
Simplemente escriba sus reglas en Python, impórtelos y ejecútelos. La vida es más simple, mucho más fácil de depurar, y en realidad resolvió el problema real de lectura de registros sin crear otro problema.
Imagina este escenario. Tu programa se rompe Ahora es el análisis de reglas, la ejecución de reglas o la regla en sí misma. Debe depurar los tres. Si escribieras la regla en Python, sería la regla, y eso sería todo.
"Creo que sería difícil filtrar el Python hasta el punto en que el usuario no podía hacer cosas locas inadvertidamente con las reglas que no se pretendía".
Este es en gran parte el argumento "Quiero escribir un compilador".
1) Eres el usuario principal. Escribirás, depurarás y mantendrás las reglas. ¿Hay realmente ejércitos de programadores locos que harán cosas locas? De Verdad? Si hay algún usuario loco potencial, hable con ellos . Enséñales No luche contra ellos inventando un nuevo idioma (que luego deberá mantener y depurar para siempre).
2) Es solo el procesamiento de registro. No hay un costo real para la locura . Nadie va a subvertir el sistema económico mundial con un manejo de registro defectuoso. No haga una pequeña tarea con unas pocas docenas de líneas de Python en un intérprete de 1000 líneas para interpretar unas pocas docenas de líneas de algún lenguaje de reglas. Solo escribe las pocas docenas de líneas de Python.
Simplemente escríbelo en Python tan rápido y claramente como puedas y pasa al siguiente proyecto.
Es posible que también desee ver PyKE .
¿Has considerado NebriOS? Acabamos de lanzar esta herramienta después de construirla para nuestros propios fines. Es un motor de reglas puro de Python / Django . En realidad lo usamos para tareas de flujo de trabajo, pero es lo suficientemente genérico como para ayudarlo en su situación. Debería conectarse al DB remoto y ejecutar las reglas en su contra.
El Python que escribió terminaría siendo más de una regla en el sistema. Aquí hay uno por ejemplo:
class SeverityRule(NebriOS):
# add listener or timer here
check(self):
if operator == ">="
return message.severity >= severity
# any number of checks here
action(self):
csv.append(message.severity, datetime.now)
send_email([email protected], """Severity level alert: {{message.severity}}""")
Compruébelo en http://nebrios.com . No me di cuenta de cuánto había para construir una aplicación de motor de reglas como Nebri hasta después de que mi equipo comenzó. Fue una tarea ENORME que va mucho más profundo de lo que parece. ACL, colas, formularios, KVPS, comprobaciones eficientes, errores útiles, análisis de correo electrónico, formularios dinámicos y la lista continúa.