Vision console is not very user friendly for logs analyse in CLIENT scope.
So you can add a RollingFileAppender for all client’s logs produced with code like :
logger = system.util.getLogger("myLogger")
if logger.isDebugEnabled():
logger.debug("Hello, world!")
(print message are not concerned and stay only in the console)
In order to route the logs to others files in parallel with the vision console, you can add a call
- to startLogClient() in your client startup script.
- to stopLogClient() in your client shutdown script.
Now, you can use an external tool like these for windows, to consult the logs : http://www.log-expert.de/ , Bare Metal Software > BareTail - Free tail for Windows or all other tailer tools or log analyse/viewer tools.
Hope this help !
appenderName = "my-vision-logs"
def startLogClient():
global appenderName
logDir = "C:/logs"
logDir = "e:/log"
logMaxFileSize = "1 MB"
logMaxIndex = 10
logPattern = "%date{yyyy/MM/dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n"
scope = getScope()
try:
if (scope in ["C","D"]):
#https://logback.qos.ch/manual
#https://logback.qos.ch/apidocs/index.html
#https://stackoverflow.com/questions/47299109/programatically-add-appender-in-logback-slf4j
#https://javaetmoi.com/2018/03/configurez-logback-en-java/
from org.slf4j import LoggerFactory
from ch.qos.logback.classic import Logger
from ch.qos.logback.classic import LoggerContext
from ch.qos.logback.classic.encoder import PatternLayoutEncoder
from ch.qos.logback.core import FileAppender
from ch.qos.logback.core.util import FileSize
from ch.qos.logback.core.rolling import RollingFileAppender
from ch.qos.logback.core.rolling import FixedWindowRollingPolicy
from ch.qos.logback.core.rolling import SizeBasedTriggeringPolicy
loggerContext = LoggerFactory.getILoggerFactory()
# to avoid file's conflict if Client and designer launched on the same machine
if scope=="C":
filename="client-vision"
else:
filename="designer"
logPath = "%s/%s.txt" % (logDir,filename)
logFileNamePattern = "%s/%s_%s.txt" % (logDir,filename,"%i")
#print logPath
#print logFileNamePattern
rfAppender = RollingFileAppender()
rfAppender.setContext(loggerContext)
rfAppender.setFile(logPath)
rfAppender.setName(appenderName)
fwRollingPolicy = FixedWindowRollingPolicy()
fwRollingPolicy.setContext(loggerContext)
fwRollingPolicy.setMinIndex(1)
fwRollingPolicy.setMaxIndex(logMaxIndex)
fwRollingPolicy.setFileNamePattern(logFileNamePattern)
fwRollingPolicy.setParent(rfAppender)
fwRollingPolicy.start()
triggeringPolicy = SizeBasedTriggeringPolicy()
triggeringPolicy.setMaxFileSize(logMaxFileSize)
triggeringPolicy.start()
encoder = PatternLayoutEncoder()
encoder.setContext(loggerContext)
encoder.setPattern(logPattern)
encoder.start()
rfAppender.setEncoder(encoder)
rfAppender.setRollingPolicy(fwRollingPolicy)
rfAppender.setTriggeringPolicy(triggeringPolicy)
rfAppender.start()
# for adding the appender for all client loggers
logbackLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)
# In case this function is called multiple times
appender = logbackLogger.getAppender(appenderName)
if appender != None:
logbackLogger.detachAppender(appenderName)
logbackLogger.addAppender(rfAppender)
except:
print "error startLogClient()"
def getScope():
from com.inductiveautomation.ignition.common.model import ApplicationScope
try:
scope = ApplicationScope.getGlobalScope()
if ApplicationScope.isGateway(scope):
# Scope Gateway
return "G"
elif ApplicationScope.isClient(scope):
# Scope Client
return "C"
elif ApplicationScope.isDesigner(scope):
# Scope Client
return "D"
else:
return "?"
except:
return "?"
def stopLogClient():
global appenderName
scope = getScope()
if (scope in ["C","D"]):
from org.slf4j import LoggerFactory
from ch.qos.logback.classic import Logger
logbackLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)
appender = logbackLogger.getAppender(appenderName)
if appender != None:
logbackLogger.detachAppender(appenderName)