От автора: этой заметкой я хотел бы начать новую волну небольших заметок и статей, которые я искренне надеюсь, подхватят и другие автоматизаторы. Ведь каждый день мы сталкиваемся с некоторыми проблемами и как то их решаем. Так давайте не только концентрироваться на поиске решения своей проблемы, а и делиться успехами и наработанным опытом. Это не должна быть статья на 3000 слов, а всего лишь 2-5 абзацев текста, а также какое-то количество вставленного кода. Просто создаем пост с нужным контентом в нужном разделе. Не так и сложно, верно? Или нет?
Кто хоть раз создавал свою библиотеку для RobotFramework знают, что это сделать вполне не сложно, а я бы сказал, что очень даже просто. Схема подключения библиотеки выглядит следующим образом:
- Выбираем библиотеку или код, на котором будет основываться наша библиотека
- Пишем код на python или java, где каждый метод класса это будет keyword в тесте
- Дальше подключаем написанный класс через импорт модуля в тесте.
Вот и все, ничего сложного.
Проблема
Так в чем собственно проблема? Есть такая библиотека SudsLibrary в RobotFramework, которая основывается на одноименной python библиотеке suds для работы с веб-сервисами. Библиотека работает как надо. Но когда запускаешь средней сложности тест с 30-50 вызовами вебсервисов на уровне логирования DEBUG (а в RobotFramework есть TRACE, DEBUG, INFO, WARN), то сама библиотека suds закидывает бесполезными логами, что логи RobotFramework-a могут вырасти до нескольких десятков мегабайт. C чем я не хочу мириться, но как же это побороть. Вроде бы нужно просто уменьшить уровень логирования в библиотеке и все должно быть нормально, но …
Как выглядит абсолютно бесполезная информация в спам логах?
20131004 20:20:30.781 : DEBUG : (u'CommonRequest', u'http://host.net/dataroamingbucket/wsdl/v1/'), found as: <Complex:0x2a65f90 name="CommonRequest" />
20131004 20:20:30.781 : DEBUG : Element:0x2adb3d0, convert type="xs:string" to (u'string', u'http://www.w3.org/2001/XMLSchema')
20131004 20:20:30.781 : DEBUG : Element:0x2adb550, convert type="xs:string" to (u'string', u'http://www.w3.org/2001/XMLSchema')
20131004 20:20:30.782 : DEBUG : Element:0x2adb490, convert type="xs:string" to (u'string', u'http://www.w3.org/2001/XMLSchema')
20131004 20:20:30.782 : DEBUG : Element:0x2adb2d0, convert type="xs:dateTime" to (u'dateTime', u'http://www.w3.org/2001/XMLSchema')
20131004 20:20:30.782 : DEBUG : Element:0x2adb270, convert type="xs:string" to (u'string', u'http://www.w3.org/2001/XMLSchema')
20131004 20:20:30.782 : DEBUG : Element:0x2adb890, convert type="xs:string" to (u'string', u'http://www.w3.org/2001/XMLSchema')
или
20131004 20:20:31.076 : DEBUG : (u'GetSmsCodeRequestType', u'http://host.net/dataroamingbucket/wsdl/v1/'), found as: <Complex:0x305c510 name="GetSmsCodeRequestType" />
20131004 20:20:31.076 : DEBUG :
Element:0x305c2f0, resolving: (u'OrderBucketRequestType', u'http://host.net/dataroamingbucket/wsdl/v1/')
using:(TypeQuery){
id = "TypeQuery:0x4a3da30"
ref[] =
"OrderBucketRequestType",
"http://host.net/dataroamingbucket/wsdl/v1/",
history[] =
<Element:0x305c2f0 name="request" type="(u'OrderBucketRequestType', u'http://host.net/dataroamingbucket/wsdl/v1/')" />,
resolved = False
}
20131004 20:20:31.076 : DEBUG : (u'OrderBucketRequestType', u'http://host.net/dataroamingbucket/wsdl/v1/'), found as: <Complex:0x305c3d0 name="OrderBucketRequestType" />
или
20131004 20:20:34.930 : DEBUG : TypeQuery:0x49dcb70, found builtin (string)
20131004 20:20:34.930 : DEBUG :
push: (<suds.resolver.Frame instance at 0x049DC0F8>)
<suds.resolver.Frame instance at 0x04A87C10>
<suds.resolver.Frame instance at 0x049DC0F8>
20131004 20:20:34.930 : DEBUG :
pop: (<suds.resolver.Frame instance at 0x049DC0F8>)
<suds.resolver.Frame instance at 0x04A87C10>
20131004 20:20:34.930 : DEBUG :
pop: (<suds.resolver.Frame instance at 0x04A87C10>)
Как же все таки решить проблему?
К сожалению, решение данной проблемы не такое уж простое, как я бы хотел. Потому, что suds библиотека использует встроенный модуль логирования logging, а RobotFramework свой. Отключить логирование для конкретного модуля не представляется возможным, точнее все мои попытки это сделать не увенчались успехом.
Пробовал, вот так вот в коде
import logging
logging.basicConfig(level=logging.INFO)
my_logger = logging.getLogger('suds.client')
my_logger.setLevel(0)
my_logger.disabled = True
my_logger.propagate = False
Но увы ничего с этого не работает, работает только полное отключение какого-то уровня логирования.
logging.disable(logging.DEBUG)
А вот полностью, отключать мне не хочется, потому я делаю следующий хак.
Решение
Создаю свою библиотеку, которая будет расширять функциональность SudsLibrary и там создаю декоратор, который будет отключать уровень логирования перед вызовом нужного метода и включать его обратно после выполнения. Все что нужно будет мне сделать после этого, вызвать нужный декоратор на нужном методе.
Код выглядит так:
from SudsLibrary import SudsLibrary
from robot.api import logger
from functools import wraps, partial
import logging
logging.basicConfig(level=logging.INFO)
def disable_logging(function):
@wraps(function)
def wrapper(*args, **kwargs):
logger.debug("Temporarily stop DEBUG logging to reduce size of log\n"
"Please enable thru SudsLibraryExtended if you needed")
logging.disable(logging.DEBUG)
results = function(*args, **kwargs)
logging.disable(0)
logger.debug("Start DEBUG logging back")
return results
wrapper.__wrapped__ = function
return wrapper
class SudsLibraryExtended(SudsLibrary):
ROBOT_LIBRARY_SCOPE = "GLOBAL"
@disable_logging
def create_soap_client(self, *argv, **kwargv):
super(SudsLibraryExtended, self).create_soap_client(*argv, **kwargv)
@disable_logging
def _call(*argv, **kwargv):
super(SudsLibraryExtended, self)._call(*argv, **kwargv):
Теперь конечно мне надо будет уже использовать мою библиотеку, а не оригинальную. Например, вот так вот:
*** Settings ***
Force Tags smoke webservices
Library SudsLibraryExtended
*** Test Cases ***
CAPI Create Sale Order
[Tags] capi
Create Soap Client ${ENV['WSDL']}
Set Http Authentication ${ENV['USERNAME']} ${ENV['PASSWORD']}
Set Return Xml True
${response} Call Soap Method createOrder something
Log ${response}
Итог
Быстрое и простое решение возникшей проблемы с помощью logging и декораторов в python, которым я хотел с вами поделиться.
От автора: очень жду похожих заметок. Просто создаем пост в нужном разделе с нужным контентом. Можно даже просто показать какой-то кусок кода, который Вы считаете делает что-то полезное и описать его немного.