Merge branch '111-improve-the-logging-process' into 'develop'

Resolve "Improve the logging process"

See merge request slumber/multi-user!42
This commit is contained in:
Swann Martinez
2020-09-15 11:03:42 +00:00
11 changed files with 235 additions and 105 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -299,8 +299,8 @@ Here is a quick list of available actions:
.. _advanced:
Advanced configuration
======================
Advanced settings
=================
This section contains optional settings to configure the session behavior.
@ -309,7 +309,14 @@ This section contains optional settings to configure the session behavior.
Advanced configuration panel
.. rubric:: Network panel
-------
Network
-------
.. figure:: img/quickstart_advanced_network.png
:align: center
Advanced network settings
**IPC Port** is the port used for Inter Process Communication. This port is used
by the multi-users subprocesses to communicate with each others. If different instances
@ -323,7 +330,14 @@ of the multi-user are using the same IPC port it will create conflict !
**Timeout (in milliseconds)** is the maximum ping authorized before auto-disconnecting.
You should only increase it if you have a bad connection.
.. rubric:: Replication panel
-----------
Replication
-----------
.. figure:: img/quickstart_advanced_replication.png
:align: center
Advanced replication settings
**Synchronize render settings** (only host) enable replication of EEVEE and CYCLES render settings to match render between clients.
@ -341,4 +355,25 @@ You should only increase it if you have a bad connection.
- **Refresh**: pushed data update rate (in second)
- **Apply**: pulled data update rate (in second)
---
Log
---
.. figure:: img/quickstart_advanced_logging.png
:align: center
Advanced log settings
**log level** allow to set the logging level of detail. Here is the detail for each values:
+-----------+-----------------------------------------------+
| Log level | Description |
+===========+===============================================+
| ERROR | Shows only critical error |
+-----------+-----------------------------------------------+
| WARNING | Shows only errors (all kind) |
+-----------+-----------------------------------------------+
| INFO | Shows only status related messages and errors |
+-----------+-----------------------------------------------+
| DEBUG | Shows every possible information. |
+-----------+-----------------------------------------------+

View File

@ -199,11 +199,11 @@ You can run the dedicated server on any platform by following those steps:
replication.serve
.. hint::
You can also specify a custom **port** (-p), **timeout** (-t) and **admin password** (-pwd) with the following optionnal argument
You can also specify a custom **port** (-p), **timeout** (-t), **admin password** (-pwd), **log level(ERROR, WARNING, INFO or DEBUG)** (-l) and **log file** (-lf) with the following optionnal argument
.. code-block:: bash
replication.serve -p 5555 -pwd toto -t 1000
replication.serve -p 5555 -pwd toto -t 1000 -l INFO -lf server.log
As soon as the dedicated server is running, you can connect to it from blender (follow :ref:`how-to-join`).

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

@ -25,7 +25,7 @@ from pathlib import Path
import socket
import re
VERSION_EXPR = re.compile('\d+\.\d+\.\d+')
VERSION_EXPR = re.compile('\d+\.\d+\.\d+\w\d+')
THIRD_PARTY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "libs")
DEFAULT_CACHE_DIR = os.path.join(
@ -67,7 +67,6 @@ def check_package_version(name, required_version):
out = subprocess.run(f"{str(PYTHON_PATH)} -m pip show {name}", capture_output=True)
version = VERSION_EXPR.search(out.stdout.decode())
if version and version.group() == required_version:
logging.info(f"{name} is up to date")
return True

View File

@ -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()
@ -187,7 +212,8 @@ class SessionStartOperator(bpy.types.Operator):
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:
@ -672,8 +702,6 @@ def register():
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")
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,11 +285,18 @@ 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.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="")
@ -297,19 +305,28 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
net_section_row.prop(settings, "connection_timeout", text="")
replication_section = layout.row().box()
replication_section.label(text="Replication ", icon='TRIA_DOWN')
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="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_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)
@ -338,6 +355,18 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
replication_timers.label(text="Update rate (ms):")
replication_timers.prop(settings, "depsgraph_update_rate", text="")
log_section = layout.row().box()
log_section.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 = log_section.row()
log_section_row.label(text="Log 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 +385,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 +431,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 +515,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 +586,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 +605,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

@ -82,5 +82,13 @@ def resolve_from_id(id, optionnal_type=None):
def get_preferences():
return bpy.context.preferences.addons[__package__].preferences
def current_milli_time():
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'