feat: logging to files

feat: logging level

Related to #111
This commit is contained in:
Swann 2020-09-15 12:31:46 +02:00
parent 086876ad2e
commit 514f90d602
No known key found for this signature in database
GPG Key ID: E1D3641A7C43AACB
5 changed files with 192 additions and 97 deletions

View File

@ -44,13 +44,16 @@ from . import environment, utils
DEPENDENCIES = {
("replication", '0.0.21a5'),
("replication", '0.0.21a6'),
}
def register():
# Setup logging policy
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
logging.basicConfig(
format='%(asctime)s CLIENT %(levelname)-8s %(message)s',
datefmt='%H:%M:%S',
level=logging.INFO)
try:
environment.setup(DEPENDENCIES, bpy.app.binary_path_python)

View File

@ -34,8 +34,8 @@ from bpy.app.handlers import persistent
from . import bl_types, delayable, environment, presence, ui, utils
from replication.constants import (FETCHED, STATE_ACTIVE,
STATE_INITIAL,
STATE_SYNCING, RP_COMMON, UP)
STATE_INITIAL,
STATE_SYNCING, RP_COMMON, UP)
from replication.data import ReplicatedDataFactory
from replication.exception import NonAuthorizedOperationError
from replication.interface import Session
@ -71,6 +71,29 @@ class SessionStartOperator(bpy.types.Operator):
users.clear()
delayables.clear()
logging.getLogger().handlers.clear()
# logging.basicConfig(level=settings.logging_level)
formatter = logging.Formatter(
fmt='%(asctime)s CLIENT %(levelname)-8s %(message)s',
datefmt='%H:%M:%S'
)
log_directory = os.path.join(
settings.cache_directory,
"multiuser_client.log")
os.makedirs(settings.cache_directory, exist_ok=True)
logger = logging.getLogger()
handler = logging.FileHandler(log_directory, mode='w')
logger.addHandler(handler)
for handler in logger.handlers:
if isinstance(handler, logging.NullHandler):
continue
handler.setFormatter(formatter)
bpy_factory = ReplicatedDataFactory()
supported_bl_types = []
@ -104,7 +127,8 @@ class SessionStartOperator(bpy.types.Operator):
external_update_handling=use_extern_update)
if settings.update_method == 'DEPSGRAPH':
delayables.append(delayable.ApplyTimer(settings.depsgraph_update_rate/1000))
delayables.append(delayable.ApplyTimer(
settings.depsgraph_update_rate/1000))
# Host a session
if self.host:
@ -123,7 +147,10 @@ class SessionStartOperator(bpy.types.Operator):
port=settings.port,
ipc_port=settings.ipc_port,
timeout=settings.connection_timeout,
password=admin_pass
password=admin_pass,
cache_directory=settings.cache_directory,
server_log_level=logging.getLevelName(
logging.getLogger().level),
)
except Exception as e:
self.report({'ERROR'}, repr(e))
@ -162,7 +189,6 @@ class SessionStartOperator(bpy.types.Operator):
delayables.append(session_update)
delayables.append(session_user_sync)
@client.register('on_connection')
def initialize_session():
settings = utils.get_preferences()
@ -177,7 +203,6 @@ class SessionStartOperator(bpy.types.Operator):
if node_ref.state == FETCHED:
node_ref.apply()
# Launch drawing module
if runtime_settings.enable_presence:
presence.renderer.run()
@ -185,9 +210,10 @@ class SessionStartOperator(bpy.types.Operator):
# Register blender main thread tools
for d in delayables:
d.register()
if settings.update_method == 'DEPSGRAPH':
bpy.app.handlers.depsgraph_update_post.append(depsgraph_evaluation)
bpy.app.handlers.depsgraph_update_post.append(
depsgraph_evaluation)
@client.register('on_exit')
def desinitialize_session():
@ -204,7 +230,8 @@ class SessionStartOperator(bpy.types.Operator):
presence.renderer.stop()
if settings.update_method == 'DEPSGRAPH':
bpy.app.handlers.depsgraph_update_post.remove(depsgraph_evaluation)
bpy.app.handlers.depsgraph_update_post.remove(
depsgraph_evaluation)
bpy.ops.session.apply_armature_operator()
@ -422,14 +449,16 @@ class SessionSnapUserOperator(bpy.types.Operator):
if target_scene != context.scene.name:
blender_scene = bpy.data.scenes.get(target_scene, None)
if blender_scene is None:
self.report({'ERROR'}, f"Scene {target_scene} doesn't exist on the local client.")
self.report(
{'ERROR'}, f"Scene {target_scene} doesn't exist on the local client.")
session_sessings.time_snap_running = False
return {"CANCELLED"}
bpy.context.window.scene = blender_scene
# Update client viewmatrix
client_vmatrix = target_ref['metadata'].get('view_matrix', None)
client_vmatrix = target_ref['metadata'].get(
'view_matrix', None)
if client_vmatrix:
rv3d.view_matrix = mathutils.Matrix(client_vmatrix)
@ -625,6 +654,7 @@ def update_client_frame(scene):
'frame_current': scene.frame_current
})
@persistent
def depsgraph_evaluation(scene):
if client and client.state['STATE'] == STATE_ACTIVE:
@ -640,7 +670,7 @@ def depsgraph_evaluation(scene):
if update.id.uuid:
# Retrieve local version
node = client.get(update.id.uuid)
# Check our right on this update:
# - if its ours or ( under common and diff), launch the
# update process
@ -648,7 +678,7 @@ def depsgraph_evaluation(scene):
if node and node.owner in [client.id, RP_COMMON] and node.state == UP:
# Avoid slow geometry update
if 'EDIT' in context.mode and \
not settings.enable_editmode_updates:
not settings.enable_editmode_updates:
break
client.stash(node.uuid)
@ -671,8 +701,6 @@ def register():
bpy.app.handlers.load_pre.append(load_pre_handler)
bpy.app.handlers.frame_change_pre.append(update_client_frame)
def unregister():
global client
@ -690,4 +718,3 @@ def unregister():
bpy.app.handlers.load_pre.remove(load_pre_handler)
bpy.app.handlers.frame_change_pre.remove(update_client_frame)

View File

@ -21,7 +21,8 @@ import bpy
import string
import re
from . import utils, bl_types, environment, addon_updater_ops, presence, ui
from . import bl_types, environment, addon_updater_ops, presence, ui
from .utils import get_preferences, get_expanded_icon
from replication.constants import RP_COMMON
IP_EXPR = re.compile('\d+\.\d+\.\d+\.\d+')
@ -46,6 +47,7 @@ def update_panel_category(self, context):
ui.SESSION_PT_settings.bl_category = self.panel_category
ui.register()
def update_ip(self, context):
ip = IP_EXPR.search(self.ip)
@ -55,14 +57,25 @@ def update_ip(self, context):
logging.error("Wrong IP format")
self['ip'] = "127.0.0.1"
def update_port(self, context):
max_port = self.port + 3
if self.ipc_port < max_port and \
self['ipc_port'] >= self.port:
logging.error("IPC Port in conflic with the port, assigning a random value")
self['ipc_port'] >= self.port:
logging.error(
"IPC Port in conflic with the port, assigning a random value")
self['ipc_port'] = random.randrange(self.port+4, 10000)
def set_log_level(self, value):
logging.getLogger().setLevel(value)
def get_log_level(self):
return logging.getLogger().level
class ReplicatedDatablock(bpy.types.PropertyGroup):
type_name: bpy.props.StringProperty()
bl_name: bpy.props.StringProperty()
@ -134,7 +147,8 @@ class SessionPrefs(bpy.types.AddonPreferences):
description='replication update method',
items=[
('DEFAULT', "Default", "Default: Use threads to monitor databloc changes"),
('DEPSGRAPH', "Depsgraph", "Experimental: Use the blender dependency graph to trigger updates"),
('DEPSGRAPH', "Depsgraph",
"Experimental: Use the blender dependency graph to trigger updates"),
],
)
# Replication update settings
@ -158,17 +172,18 @@ class SessionPrefs(bpy.types.AddonPreferences):
],
default='CONFIG'
)
# WIP
logging_level: bpy.props.EnumProperty(
name="Log level",
description="Log verbosity level",
items=[
('ERROR', "error", "show only errors"),
('WARNING', "warning", "only show warnings and errors"),
('INFO', "info", "default level"),
('DEBUG', "debug", "show all logs"),
('ERROR', "error", "show only errors", logging.ERROR),
('WARNING', "warning", "only show warnings and errors", logging.WARNING),
('INFO', "info", "default level", logging.INFO),
('DEBUG', "debug", "show all logs", logging.DEBUG),
],
default='INFO'
default='INFO',
set=set_log_level,
get=get_log_level
)
conf_session_identity_expanded: bpy.props.BoolProperty(
name="Identity",
@ -200,7 +215,21 @@ class SessionPrefs(bpy.types.AddonPreferences):
description="Interface",
default=False
)
sidebar_advanced_rep_expanded: bpy.props.BoolProperty(
name="sidebar_advanced_rep_expanded",
description="sidebar_advanced_rep_expanded",
default=False
)
sidebar_advanced_log_expanded: bpy.props.BoolProperty(
name="sidebar_advanced_log_expanded",
description="sidebar_advanced_log_expanded",
default=False
)
sidebar_advanced_net_expanded: bpy.props.BoolProperty(
name="sidebar_advanced_net_expanded",
description="sidebar_advanced_net_expanded",
default=False
)
auto_check_update: bpy.props.BoolProperty(
name="Auto-check for Update",
description="If enabled, auto-check for updates using an interval",
@ -252,8 +281,8 @@ class SessionPrefs(bpy.types.AddonPreferences):
box = grid.box()
box.prop(
self, "conf_session_identity_expanded", text="User informations",
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_identity_expanded
else 'DISCLOSURE_TRI_RIGHT', emboss=False)
icon=get_expanded_icon(self.conf_session_identity_expanded),
emboss=False)
if self.conf_session_identity_expanded:
box.row().prop(self, "username", text="name")
box.row().prop(self, "client_color", text="color")
@ -262,8 +291,8 @@ class SessionPrefs(bpy.types.AddonPreferences):
box = grid.box()
box.prop(
self, "conf_session_net_expanded", text="Netorking",
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_net_expanded
else 'DISCLOSURE_TRI_RIGHT', emboss=False)
icon=get_expanded_icon(self.conf_session_net_expanded),
emboss=False)
if self.conf_session_net_expanded:
box.row().prop(self, "ip", text="Address")
@ -280,8 +309,8 @@ class SessionPrefs(bpy.types.AddonPreferences):
table = box.box()
table.row().prop(
self, "conf_session_timing_expanded", text="Refresh rates",
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_timing_expanded
else 'DISCLOSURE_TRI_RIGHT', emboss=False)
icon=get_expanded_icon(self.conf_session_timing_expanded),
emboss=False)
if self.conf_session_timing_expanded:
line = table.row()
@ -299,8 +328,8 @@ class SessionPrefs(bpy.types.AddonPreferences):
box = grid.box()
box.prop(
self, "conf_session_hosting_expanded", text="Hosting",
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_hosting_expanded
else 'DISCLOSURE_TRI_RIGHT', emboss=False)
icon=get_expanded_icon(self.conf_session_hosting_expanded),
emboss=False)
if self.conf_session_hosting_expanded:
row = box.row()
row.label(text="Init the session from:")
@ -310,8 +339,8 @@ class SessionPrefs(bpy.types.AddonPreferences):
box = grid.box()
box.prop(
self, "conf_session_cache_expanded", text="Cache",
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_cache_expanded
else 'DISCLOSURE_TRI_RIGHT', emboss=False)
icon=get_expanded_icon(self.conf_session_cache_expanded),
emboss=False)
if self.conf_session_cache_expanded:
box.row().prop(self, "cache_directory", text="Cache directory")
@ -319,7 +348,7 @@ class SessionPrefs(bpy.types.AddonPreferences):
box = grid.box()
box.prop(
self, "conf_session_ui_expanded", text="Interface",
icon='DISCLOSURE_TRI_DOWN' if self.conf_session_ui_expanded else 'DISCLOSURE_TRI_RIGHT',
icon=get_expanded_icon(self.conf_session_ui_expanded),
emboss=False)
if self.conf_session_ui_expanded:
box.row().prop(self, "panel_category", text="Panel category", expand=True)
@ -353,7 +382,7 @@ def client_list_callback(scene, context):
items = [(RP_COMMON, RP_COMMON, "")]
username = utils.get_preferences().username
username = get_preferences().username
cli = operators.client
if cli:
client_ids = cli.online_users.keys()

View File

@ -18,7 +18,8 @@
import bpy
from . import operators, utils
from . import operators
from .utils import get_preferences, get_expanded_icon
from replication.constants import (ADDED, ERROR, FETCHED,
MODIFIED, RP_COMMON, UP,
STATE_ACTIVE, STATE_AUTH,
@ -112,7 +113,7 @@ class SESSION_PT_settings(bpy.types.Panel):
layout.use_property_split = True
row = layout.row()
runtime_settings = context.window_manager.session
settings = utils.get_preferences()
settings = get_preferences()
if hasattr(context.window_manager, 'session'):
# STATE INITIAL
@ -195,7 +196,7 @@ class SESSION_PT_settings_network(bpy.types.Panel):
layout = self.layout
runtime_settings = context.window_manager.session
settings = utils.get_preferences()
settings = get_preferences()
# USER SETTINGS
row = layout.row()
@ -253,7 +254,7 @@ class SESSION_PT_settings_user(bpy.types.Panel):
layout = self.layout
runtime_settings = context.window_manager.session
settings = utils.get_preferences()
settings = get_preferences()
row = layout.row()
# USER SETTINGS
@ -284,60 +285,87 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
layout = self.layout
runtime_settings = context.window_manager.session
settings = utils.get_preferences()
settings = get_preferences()
net_section = layout.row().box()
net_section.label(text="Network ", icon='TRIA_DOWN')
net_section_row = net_section.row()
net_section_row.label(text="IPC Port:")
net_section_row.prop(settings, "ipc_port", text="")
net_section_row = net_section.row()
net_section_row.label(text="Timeout (ms):")
net_section_row.prop(settings, "connection_timeout", text="")
net_section.prop(
settings,
"sidebar_advanced_net_expanded",
text="Network",
icon=get_expanded_icon(settings.sidebar_advanced_net_expanded),
emboss=False)
if settings.sidebar_advanced_net_expanded:
net_section_row = net_section.row()
net_section_row.label(text="IPC Port:")
net_section_row.prop(settings, "ipc_port", text="")
net_section_row = net_section.row()
net_section_row.label(text="Timeout (ms):")
net_section_row.prop(settings, "connection_timeout", text="")
replication_section = layout.row().box()
replication_section.label(text="Replication ", icon='TRIA_DOWN')
replication_section_row = replication_section.row()
replication_section_row.label(text="Sync flags", icon='COLLECTION_NEW')
replication_section_row = replication_section.row()
replication_section_row.prop(settings.sync_flags, "sync_render_settings")
replication_section_row = replication_section.row()
# replication_section_row.label(text=":", icon='EDITMODE_HLT')
replication_section_row.prop(settings, "enable_editmode_updates")
replication_section_row = replication_section.row()
if settings.enable_editmode_updates:
warning = replication_section_row.box()
warning.label(text="Don't use this with heavy meshes !", icon='ERROR')
replication_section.prop(
settings,
"sidebar_advanced_rep_expanded",
text="Replication",
icon=get_expanded_icon(settings.sidebar_advanced_rep_expanded),
emboss=False)
if settings.sidebar_advanced_rep_expanded:
replication_section_row = replication_section.row()
replication_section_row.label(text="Update method", icon='RECOVER_LAST')
replication_section_row = replication_section.row()
replication_section_row.prop(settings, "update_method", expand=True)
replication_section_row = replication_section.row()
replication_timers = replication_section_row.box()
replication_timers.label(text="Replication timers", icon='TIME')
if settings.update_method == "DEFAULT":
replication_timers = replication_timers.row()
# Replication frequencies
flow = replication_timers.grid_flow(
row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
line = flow.row(align=True)
line.label(text=" ")
line.separator()
line.label(text="refresh (sec)")
line.label(text="apply (sec)")
for item in settings.supported_datablocks:
replication_section_row.label(text="Sync flags", icon='COLLECTION_NEW')
replication_section_row = replication_section.row()
replication_section_row.prop(settings.sync_flags, "sync_render_settings")
replication_section_row = replication_section.row()
replication_section_row.prop(settings, "enable_editmode_updates")
replication_section_row = replication_section.row()
if settings.enable_editmode_updates:
warning = replication_section_row.box()
warning.label(text="Don't use this with heavy meshes !", icon='ERROR')
replication_section_row = replication_section.row()
replication_section_row.label(text="Update method", icon='RECOVER_LAST')
replication_section_row = replication_section.row()
replication_section_row.prop(settings, "update_method", expand=True)
replication_section_row = replication_section.row()
replication_timers = replication_section_row.box()
replication_timers.label(text="Replication timers", icon='TIME')
if settings.update_method == "DEFAULT":
replication_timers = replication_timers.row()
# Replication frequencies
flow = replication_timers.grid_flow(
row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
line = flow.row(align=True)
line.prop(item, "auto_push", text="", icon=item.icon)
line.label(text=" ")
line.separator()
line.prop(item, "bl_delay_refresh", text="")
line.prop(item, "bl_delay_apply", text="")
else:
replication_timers = replication_timers.row()
replication_timers.label(text="Update rate (ms):")
replication_timers.prop(settings, "depsgraph_update_rate", text="")
line.label(text="refresh (sec)")
line.label(text="apply (sec)")
for item in settings.supported_datablocks:
line = flow.row(align=True)
line.prop(item, "auto_push", text="", icon=item.icon)
line.separator()
line.prop(item, "bl_delay_refresh", text="")
line.prop(item, "bl_delay_apply", text="")
else:
replication_timers = replication_timers.row()
replication_timers.label(text="Update rate (ms):")
replication_timers.prop(settings, "depsgraph_update_rate", text="")
log_section_row = layout.row().box()
log_section_row.prop(
settings,
"sidebar_advanced_log_expanded",
text="Logging",
icon=get_expanded_icon(settings.sidebar_advanced_log_expanded),
emboss=False)
if settings.sidebar_advanced_log_expanded:
log_section_row.label(text="Logging level:")
log_section_row.prop(settings, 'logging_level', text="")
class SESSION_PT_user(bpy.types.Panel):
bl_idname = "MULTIUSER_USER_PT_panel"
bl_label = "Online users"
@ -356,7 +384,7 @@ class SESSION_PT_user(bpy.types.Panel):
layout = self.layout
online_users = context.window_manager.online_users
selected_user = context.window_manager.user_index
settings = utils.get_preferences()
settings = get_preferences()
active_user = online_users[selected_user] if len(
online_users)-1 >= selected_user else 0
runtime_settings = context.window_manager.session
@ -402,7 +430,7 @@ class SESSION_PT_user(bpy.types.Panel):
class SESSION_UL_users(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):
session = operators.client
settings = utils.get_preferences()
settings = get_preferences()
is_local_user = item.username == settings.username
ping = '-'
frame_current = '-'
@ -486,7 +514,7 @@ class SESSION_PT_services(bpy.types.Panel):
def draw_property(context, parent, property_uuid, level=0):
settings = utils.get_preferences()
settings = get_preferences()
runtime_settings = context.window_manager.session
item = operators.client.get(uuid=property_uuid)
@ -557,7 +585,7 @@ class SESSION_PT_repository(bpy.types.Panel):
@classmethod
def poll(cls, context):
session = operators.client
settings = utils.get_preferences()
settings = get_preferences()
admin = False
if session and hasattr(session,'online_users'):
@ -576,7 +604,7 @@ class SESSION_PT_repository(bpy.types.Panel):
layout = self.layout
# Filters
settings = utils.get_preferences()
settings = get_preferences()
runtime_settings = context.window_manager.session
session = operators.client

View File

@ -39,7 +39,7 @@ def find_from_attr(attr_name, attr_value, list):
def get_datablock_users(datablock):
users = []
supported_types = get_preferences().supported_datablocks
supported_types = get_preferences().supported_datablocks
if hasattr(datablock, 'users_collection') and datablock.users_collection:
users.extend(list(datablock.users_collection))
if hasattr(datablock, 'users_scene') and datablock.users_scene:
@ -77,10 +77,18 @@ def resolve_from_id(id, optionnal_type=None):
if id in root and ((optionnal_type is None) or (optionnal_type.lower() in root[id].__class__.__name__.lower())):
return root[id]
return None
def get_preferences():
return bpy.context.preferences.addons[__package__].preferences
def current_milli_time():
return int(round(time.time() * 1000))
return int(round(time.time() * 1000))
def get_expanded_icon(prop: bpy.types.BoolProperty) -> str:
if prop:
return 'DISCLOSURE_TRI_DOWN'
else:
return 'DISCLOSURE_TRI_RIGHT'