Permalink
Browse files

Adding new custom logger stuff.

  • Loading branch information...
captainhammy committed Dec 15, 2018
1 parent 2c22bec commit 4fcad69356f072f8b051d47723e6054130c0e1d8
@@ -11,6 +11,8 @@ source =
ht.events.events.rop_render
ht.events.events.scene_load
ht.inline.api
ht.logger
ht.loggers.shellio
ht.nodes.styles.event
ht.nodes.styles.styles
ht.nodes.styles.manager
@@ -19,6 +21,7 @@ source =
ht.pyfilter.utils
ht.pyfilter.operations.deepimage
ht.pyfilter.operations.ipoverrides
ht.pyfilter.operations.logoutput
ht.pyfilter.operations.operation
ht.pyfilter.operations.primaryimage
ht.pyfilter.operations.zdepth
@@ -11,7 +11,7 @@
# =============================================================================

# Houdini Toolbox Imports
from ht.pyfilter.logger import logger
from ht.logger import logger
from ht.pyfilter.manager import PyFilterManager

# Houdini Imports
@@ -1,11 +1,12 @@
{
"operations":
[
["ht.pyfilter.operations.setproperties", "SetProperties"],
["ht.pyfilter.operations.deepimage", "SetDeepImage"],
["ht.pyfilter.operations.zdepth", "ZDepthPass"],
["ht.pyfilter.operations.settilecallback", "SetTileCallback"],
["ht.pyfilter.operations.ipoverrides", "IpOverrides"],
["ht.pyfilter.operations.primaryimage", "SetPrimaryImage"]
["ht.pyfilter.operations.logoutput", "LogOutput"],
["ht.pyfilter.operations.primaryimage", "SetPrimaryImage"],
["ht.pyfilter.operations.setproperties", "SetProperties"],
["ht.pyfilter.operations.settilecallback", "SetTileCallback"],
["ht.pyfilter.operations.zdepth", "ZDepthPass"]
]
}
@@ -5,10 +5,19 @@
# =============================================================================

# Houdini Toolbox Imports

# We want to initialize our logger first thing before the UI starts so that our
# base stream logger is using the actual sys.stdout/shell output. If we don't
# then it will use sys.stdout which is redirected to any interactive Python
# Shell panes. We explicitly provide an alternate stream handler for output
# to only these pane tabs.
import ht.logger

import ht.events
import ht.events.callbacks
import ht.sohohooks.aovs
import ht.nodes.styles

# Create any dynamic event handlers, such as using Python's atexit module
ht.events.callbacks.register_callbacks()

@@ -424,6 +424,7 @@ def _buildParser():
help="The Python logging level.",
default="INFO",
choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
dest="log_level"
)

parser.add_argument(
@@ -0,0 +1,90 @@
"""Base logger for Houdini-Toolbox."""

# =============================================================================
# IMPORTS
# =============================================================================

# Python Imports
import logging
import logging.config
import os
import yaml

# =============================================================================
# NON-PUBLIC FUNCTIONS
# =============================================================================

def _get_default_log_level():
"""Get the initial log level.
If $HT_LOG_LEVEL is set it will be used, otherwise the default will be
"INFO".
:return: The default log level.
:rtype: int
"""
level = os.getenv("HT_LOG_LEVEL", "INFO")

return _log_level_from_string(level)


def _init_logger_config():
"""Load logger config from file.
:return:
"""
config_path = os.path.join(os.path.dirname(__file__), "loggers", "config.yaml")

if os.path.exists(config_path):
with open(config_path, 'r') as f:
config = yaml.safe_load(f.read())
logging.config.dictConfig(config)


def _log_level_from_string(level):
"""Get a logging level from a string.
This will attempt to get the uppercase version of the level as an attribute
from the logging module.
:param level: The level as a string.
:type level: str
:return: A matching logging level, otherwise None.
:rtype: int
"""
return getattr(logging, level.upper())

# =============================================================================
# FUNCTIONS
# =============================================================================

def get_logger(name, level=None):
"""Get a named logger, optionally set to a specified level.
:param name: The name of the logger.
:type name: str
:param level: The level to set.
:type level: str
:return: A logger with a given name.
:rtype: logging.logger
"""
_logger = logging.getLogger(name)

if level is not None:
_logger.setLevel(_log_level_from_string(level))

# Set the logger to the default level.
else:
_logger.setLevel(_get_default_log_level())

return _logger

# =============================================================================

_init_logger_config()

logger = get_logger("Houdini-Toolbox")
No changes.
@@ -0,0 +1,28 @@

version: 1
formatters:
default:
format: '%(asctime)s %(levelname)-8s %(name)s | %(message)s'
datefmt: '%H:%M:%S'
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: default
stream: ext://sys.stdout
python_shell:
class: ht.loggers.shellio.PythonShellHandler
level: WARNING
formatter: default
loggers:
Houdini-Toolbox:
level: DEBUG
handlers: [console, python_shell]
propagate: no
mantra:
level: DEBUG
handlers: [console]
propagate: no
root:
level: INFO
handlers: [console]
@@ -0,0 +1,44 @@
"""Custom logging stream handler which writes to Houdini Python Shell panels."""

# =============================================================================
# IMPORTS
# =============================================================================

# Python Imports
import logging
import sys

# Houdini Imports
import hou

# =============================================================================
# CLASSES
# =============================================================================

class PythonShellHandler(logging.StreamHandler):
"""Custom stream handler which outputs to the interactive Python shell
when it is open.
Houdini will redirect sys.stdout to be an instance of hou.ShellIO when there
is a Python Shell panel active and displayed. This handler works by checking
that sys.stdout is a hou.ShellIO and writes output to it accordingly. If
it is not, no output will be written.
"""

def emit(self, record):
try:
msg = self.format(record)

stream = sys.stdout

if isinstance(stream, hou.ShellIO):
stream.write(msg)
stream.write('\n')
stream.flush()

except (KeyboardInterrupt, SystemExit):
raise

except:
self.handleError(record)

This file was deleted.

Oops, something went wrong.
@@ -12,7 +12,7 @@
import json

# Houdini Toolbox Imports
from ht.pyfilter.logger import logger
from ht.logger import logger

# =============================================================================
# CLASSES
@@ -5,7 +5,7 @@
# =============================================================================

# Houdini Toolbox Imports
from ht.pyfilter.logger import logger
from ht.logger import logger
from ht.pyfilter.operations.operation import PyFilterOperation, log_filter
from ht.pyfilter.property import get_property, set_property

@@ -0,0 +1,76 @@
"""This module contains an operation to log Mantra output."""

# =============================================================================
# IMPORTS
# =============================================================================

# Python Imports
import logging

# Houdini Toolbox Imports
from ht.pyfilter.operations.operation import PyFilterOperation

# =============================================================================
# CLASSES
# =============================================================================

class LogOutput(PyFilterOperation):
"""Operation to log Mantra output."""

def __init__(self, manager):
super(LogOutput, self).__init__(manager)

# Get our custom mantra logger setup via config.
self._logger = logging.getLogger("mantra")

# =========================================================================
# PROPERTIES
# =========================================================================

@property
def logger(self):
"""logging.Logger: The logger to use when outputting."""
return self._logger

# =========================================================================
# METHODS
# =========================================================================

def filterError(self, level, message, prefix):
"""Handle message outputting.
:param level: The output level.
:type level: int
:param message: The output message.
:type message: str
:param prefix: Message prefix.
:type prefix: str
:return: Return True to indicate that we handled the output so Mantra
will not.
:rtype: bool
"""
# Split message by newlines so we can log each line.
messages = message.split('\n')

for message in messages:
# Verbosity of 0 is always for errors.
if level == 0:
self.logger.error(message)

# Mantra also only seems to set the prefix if the message is an
# error/warning.
elif prefix:
self.logger.warning(message)

# Default verbosity level so we'll call that info.
elif level == 1:
self.logger.info(message)

# Flag as debug.
else:
self.logger.debug(message)

# Return True to let Mantra know that we handled message output so it
# will not output it itself.
return True
@@ -8,7 +8,7 @@
from functools import wraps

# Houdini Toolbox Imports
from ht.pyfilter.logger import logger
from ht.logger import logger

# =============================================================================
# CLASSES
@@ -5,7 +5,7 @@
# =============================================================================

# Houdini Toolbox Imports
from ht.pyfilter.logger import logger
from ht.logger import logger
from ht.pyfilter.operations.operation import PyFilterOperation, log_filter
from ht.pyfilter.property import set_property

@@ -12,15 +12,14 @@
import json

# Houdini Toolbox Imports
from ht.pyfilter.logger import logger
from ht.logger import logger
from ht.pyfilter.operations.operation import PyFilterOperation, log_filter
from ht.pyfilter.property import get_property, set_property

# =============================================================================
# CLASSES
# =============================================================================


class PropertySetterManager(object):
"""Class for creating and managing PropertySetters.
Oops, something went wrong.

0 comments on commit 4fcad69

Please sign in to comment.