Browse Source

Use standard python libraries for logging and argparsing in namespace compiler (#669)

Markus Graube 8 years ago
parent
commit
09dcc4644d

+ 0 - 2
CMakeLists.txt

@@ -296,7 +296,6 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_g
                                                 ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated
                    DEPENDS ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/${GENERATE_NAMESPACE0_FILE}
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/open62541_MacroHelper.py
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_builtin_types.py
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_constants.py
@@ -470,7 +469,6 @@ if(UA_BUILD_EXAMPLES)
                                                     ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml
                                                     ${PROJECT_BINARY_DIR}/src_generated/nodeset
                       DEPENDS ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
-                              ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py
                               ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/open62541_MacroHelper.py
                               ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_builtin_types.py
                               ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_constants.py

+ 83 - 104
tools/pyUANamespace/generate_open62541CCode.py

@@ -3,7 +3,7 @@
 
 ###
 ### Author:  Chris Iatrou (ichrispa@core-vector.net)
-### Version: rev 13
+### Version: rev 14
 ###
 ### This program was created for educational purposes and has been
 ### contributed to the open62541 project by the author. All licensing
@@ -17,87 +17,67 @@
 ###
 
 from __future__ import print_function
-from sys import argv, exit
-from os import path
 from ua_namespace import *
-from logger import *
+import logging
+import argparse
 from open62541_XMLPreprocessor import open62541_XMLPreprocessor
 
-def usage():
-  print("Script usage:")
-  print("generate_open62541CCode [-i <ignorefile> | -b <blacklistfile>] <namespace XML> [namespace.xml[ namespace.xml[...]]] <output file>\n")
-  print("generate_open62541CCode will first read all XML files passed on the command line, then ")
-  print("link and check the namespace. All nodes that fullfill the basic requirements will then be")
-  print("printed as C-Code intended to be included in the open62541 OPC-UA Server that will")
-  print("initialize the corresponding name space.\n")
-  print("Manditory Arguments:")
-  print("<namespace XML>    At least one Namespace XML file must be passed.")
-  print("<output file>      The basename for the <output file>.c and <output file>.h files to be generated.")
-  print("                   This will also be the function name used in the header and c-file.\n\n")
-  print("Additional Arguments:")
-  print("""   -i <ignoreFile>     Loads a list of NodeIDs stored in ignoreFile (one NodeID per line)
-                       The compiler will assume that these Nodes have been created externally
-                       and not generate any code for them. They will however be linked to
-                       from other nodes.""")
-  print("""   -b <blacklistFile>  Loads a list of NodeIDs stored in blacklistFile (one NodeID per line)
-                       Any of the nodeIds encountered in this file will be removed from the namespace
-                       prior to compilation. Any references to these nodes will also be removed""")
-  print("""   -s <attribute>  Suppresses the generation of some node attributes. Currently supported
-                       options are 'description', 'browseName', 'displayName', 'writeMask', 'userWriteMask'
-                       and 'nodeid'.""")
-  print("""   namespaceXML Any number of namespace descriptions in XML format. Note that the
-                       last description of a node encountered will be used and all prior definitions
-                       are discarded.""")
+logger = logging.getLogger(__name__)
+
+parser = argparse.ArgumentParser(
+    description="""Parse OPC UA NamespaceXML file(s) and create C code for generating nodes in open62541
+
+generate_open62541CCode.py will first read all XML files passed on the command line, then link and check the namespace. All nodes that fulfill the basic requirements will then be printed as C-Code intended to be included in the open62541 OPC UA Server that will initialize the corresponding namespace.""",
+    formatter_class=argparse.RawDescriptionHelpFormatter)
+parser.add_argument('infiles',
+                    metavar="<namespaceXML>",
+                    nargs='+',
+                    type=argparse.FileType('r'),
+                    help='Namespace XML file(s). Note that the last definition of a node encountered will be used and all prior definitions are discarded.')
+parser.add_argument('outputFile',
+                    metavar='<outputFile>',
+                    #type=argparse.FileType('w', 0),
+                    help='The basename for the <output file>.c and <output file>.h files to be generated. This will also be the function name used in the header and c-file.')
+parser.add_argument('-i','--ignore',
+                    metavar="<ignoreFile>",
+                    type=argparse.FileType('r'),
+                    action='append',
+                    dest="ignoreFiles",
+                    default=[],
+                    help='Loads a list of NodeIDs stored in ignoreFile (one NodeID per line). The compiler will assume that these Nodes have been creathed externally and not generate any code for them. They will however be linked to from other nodes.')
+parser.add_argument('-b','--blacklist',
+                    metavar="<blacklistFile>",
+                    type=argparse.FileType('r'),
+                    action='append',
+                    dest="blacklistFiles",
+                    default=[],
+                    help='Loads a list of NodeIDs stored in blacklistFile (one NodeID per line). Any of the nodeIds encountered in this file will be removed from the namespace prior to compilation. Any references to these nodes will also be removed')
+parser.add_argument('-s','--suppress',
+                    metavar="<attribute>",
+                    action='append',
+                    dest="suppressedAttributes",
+                    choices=['description', 'browseName', 'displayName', 'writeMask', 'userWriteMask','nodeid'],
+                    default=[],
+                    help="Suppresses the generation of some node attributes. Currently supported options are 'description', 'browseName', 'displayName', 'writeMask', 'userWriteMask' and 'nodeid'.")
+
+parser.add_argument('-v','--verbose', action='count', help='Make the script more verbose. Can be applied up to 4 times')
+
+
 
 if __name__ == '__main__':
-  # Check if the parameters given correspond to actual files
-  infiles = []
-  ouffile = ""
-  ignoreFiles = []
-  blacklistFiles = []
-  supressGenerationOfAttribute=[]
-
-  GLOBAL_LOG_LEVEL = LOG_LEVEL_DEBUG
-  
-  arg_isIgnore    = False
-  arg_isBlacklist = False
-  arg_isSupress   = False
-  if len(argv) < 2:
-    usage()
-    exit(1)
-  for filename in argv[1:-1]:
-    if arg_isIgnore:
-      arg_isIgnore = False
-      if path.exists(filename):
-        ignoreFiles.append(filename)
-      else:
-        log(None, "File " + str(filename) + " does not exist.", LOG_LEVEL_ERROR)
-        usage()
-        exit(1)
-    elif arg_isBlacklist:
-      arg_isBlacklist = False
-      if path.exists(filename):
-        blacklistFiles.append(filename)
-      else:
-        log(None, "File " + str(filename) + " does not exist.", LOG_LEVEL_ERROR)
-        usage()
-        exit(1)
-    elif arg_isSupress:
-      arg_isSupress = False
-      supressGenerationOfAttribute.append(filename.lower())
-    else:
-      if path.exists(filename):
-        infiles.append(filename)
-      elif filename.lower() == "-i" or filename.lower() == "--ignore" :
-        arg_isIgnore = True
-      elif filename.lower() == "-b" or filename.lower() == "--blacklist" :
-        arg_isBlacklist = True
-      elif filename.lower() == "-s" or filename.lower() == "--suppress" :
-        arg_isSupress = True
-      else:
-        log(None, "File " + str(filename) + " does not exist.", LOG_LEVEL_ERROR)
-        usage()
-        exit(1)
+  args = parser.parse_args()
+
+  level= logging.CRITICAL
+  if (args.verbose==1):
+    level = logging.ERROR
+  elif (args.verbose==2):
+    level = logging.WARNING
+  elif (args.verbose==3):
+    level = logging.INFO
+  elif (args.verbose>=4):
+    level = logging.DEBUG
+  logging.basicConfig(level=level)
+  logger.setLevel(logging.INFO)
 
   # Creating the header is tendious. We can skip the entire process if
   # the header exists.
@@ -107,8 +87,8 @@ if __name__ == '__main__':
   #  exit(0)
 
   # Open the output file
-  outfileh = open(argv[-1]+".h", r"w+")
-  outfilec = open(argv[-1]+".c", r"w+")
+  outfileh = open(args.outputFile+".h", r"w+")
+  outfilec = open(args.outputFile+".c", r"w+")
 
   # Create a new namespace
   # Note that the name is actually completely symbolic, it has no other
@@ -119,40 +99,39 @@ if __name__ == '__main__':
 
   # Clean up the XML files by removing duplicate namespaces and unwanted prefixes
   preProc = open62541_XMLPreprocessor()
-  for xmlfile in infiles:
-    log(None, "Preprocessing " + str(xmlfile), LOG_LEVEL_INFO)
-    preProc.addDocument(xmlfile)
+  for xmlfile in args.infiles:
+    logger.info("Preprocessing " + str(xmlfile.name))
+    preProc.addDocument(xmlfile.name)
   preProc.preprocessAll()
-  
+
   for xmlfile in preProc.getPreProcessedFiles():
-    log(None, "Parsing " + str(xmlfile), LOG_LEVEL_INFO)
+    logger.info("Parsing " + str(xmlfile))
     ns.parseXML(xmlfile)
-  
+
   # We need to notify the open62541 server of the namespaces used to be able to use i.e. ns=3
   namespaceArrayNames = preProc.getUsedNamespaceArrayNames()
   for key in namespaceArrayNames:
     ns.addNamespace(key, namespaceArrayNames[key])
-    
+
   # Remove any temp files - they are not needed after the AST is created
   # Removed for debugging
   preProc.removePreprocessedFiles()
-  
+
   # Remove blacklisted nodes from the namespace
   # Doing this now ensures that unlinkable pointers will be cleanly removed
   # during sanitation.
-  for blacklist in blacklistFiles:
-    bl = open(blacklist, "r")
-    for line in bl.readlines():
+  for blacklist in args.blacklistFiles:
+    for line in blacklist.readlines():
       line = line.replace(" ","")
       id = line.replace("\n","")
       if ns.getNodeByIDString(id) == None:
-        log(None, "Can't blacklist node, namespace does currently not contain a node with id " + str(id), LOG_LEVEL_WARN)
+        logger.info("Can't blacklist node, namespace does currently not contain a node with id " + str(id))
       else:
         ns.removeNodeById(line)
-    bl.close()
+    blacklist.close()
 
   # Link the references in the namespace
-  log(None, "Linking namespace nodes and references", LOG_LEVEL_INFO)
+  logger.info("Linking namespace nodes and references")
   ns.linkOpenPointers()
 
   # Remove nodes that are not printable or contain parsing errors, such as
@@ -164,12 +143,12 @@ if __name__ == '__main__':
   # Ex. <rpm>123</rpm> is not encodable
   #     only after parsing the datatypes, it is known that
   #     rpm is encoded as a double
-  log(None, "Building datatype encoding rules", LOG_LEVEL_INFO)
+  logger.info("Building datatype encoding rules")
   ns.buildEncodingRules()
 
   # Allocate/Parse the data values. In order to do this, we must have run
   # buidEncodingRules.
-  log(None, "Allocating variables", LOG_LEVEL_INFO)
+  logger.info("Allocating variables")
   ns.allocateVariables()
 
   # Users may have manually defined some nodes in their code already (such as serverStatus).
@@ -177,26 +156,26 @@ if __name__ == '__main__':
   # converted to C-Code. That way, they will still be reffered to by other nodes, but
   # they will not be created themselves.
   ignoreNodes = []
-  for ignore in ignoreFiles:
-    ig = open(ignore, "r")
-    for line in ig.readlines():
+  for ignore in args.ignoreFiles:
+    for line in ignore.readlines():
       line = line.replace(" ","")
       id = line.replace("\n","")
       if ns.getNodeByIDString(id) == None:
-        log(None, "Can't ignore node, Namespace does currently not contain a node with id " + str(id), LOG_LEVEL_WARN)
+        logger.warn("Can't ignore node, Namespace does currently not contain a node with id " + str(id))
       else:
         ignoreNodes.append(ns.getNodeByIDString(id))
-    ig.close()
-  
+    ignore.close()
+
   # Create the C Code
-  log(None, "Generating Header", LOG_LEVEL_INFO)
+  logger.info("Generating Header")
   # Returns a tuple of (["Header","lines"],["Code","lines","generated"])
-  generatedCode=ns.printOpen62541Header(ignoreNodes, supressGenerationOfAttribute, outfilename=path.basename(argv[-1]))
+  from os.path import basename
+  generatedCode=ns.printOpen62541Header(ignoreNodes, args.suppressedAttributes, outfilename=basename(args.outputFile))
   for line in generatedCode[0]:
     outfileh.write(line+"\n")
   for line in generatedCode[1]:
     outfilec.write(line+"\n")
- 
+
   outfilec.close()
   outfileh.close()
 

+ 0 - 46
tools/pyUANamespace/logger.py

@@ -1,46 +0,0 @@
-#!/usr/bin/env/python
-# -*- coding: utf-8 -*-
-
-###
-### Author:  Chris Iatrou (ichrispa@core-vector.net)
-### Version: rev 13
-###
-### This program was created for educational purposes and has been
-### contributed to the open62541 project by the author. All licensing
-### terms for this source is inherited by the terms and conditions
-### specified for by the open62541 project (see the projects readme
-### file for more information on the LGPL terms and restrictions).
-###
-### This program is not meant to be used in a production environment. The
-### author is not liable for any complications arising due to the use of
-### this program.
-###
-
-from __future__ import print_function
-import inspect
-
-###
-### Tidy logging helpers
-###
-
-LOG_LEVEL_DEBUG  = 4
-LOG_LEVEL_INFO   = 2
-LOG_LEVEL_WARN   = 1
-LOG_LEVEL_ERROR  = 0
-LOG_LEVEL_SILENT = -1
-
-# Change the following to filter logging output
-GLOBAL_LOG_LEVEL = LOG_LEVEL_SILENT
-
-def log(callee, logstr, level=LOG_LEVEL_DEBUG):
-  prefixes = { LOG_LEVEL_DEBUG : "DBG: ",
-               LOG_LEVEL_INFO  : "INF: ",
-               LOG_LEVEL_WARN  : "WRN: ",
-               LOG_LEVEL_ERROR : "ERR: ",
-               LOG_LEVEL_SILENT: ""
-            }
-  if level <= GLOBAL_LOG_LEVEL:
-    if prefixes.has_key(level):
-      print(str(prefixes[level]) + callee.__class__.__name__ + "." + inspect.stack()[1][3] +  "(): " + logstr)
-    else:
-      print(callee.__class__.__name__  + "." + inspect.stack()[1][3] + "(): " + logstr)

+ 21 - 18
tools/pyUANamespace/open62541_MacroHelper.py

@@ -16,10 +16,13 @@
 ### this program.
 ###
 
-from logger import *
+import logging
 from ua_constants import *
 import string
 
+
+logger = logging.getLogger(__name__)
+
 __unique_item_id = 0
 
 defined_typealiases = []
@@ -34,20 +37,20 @@ class open62541_MacroHelper():
     elif node.id().s != None:
       return "UA_EXPANDEDNODEID_STRING("  + str(node.id().ns) + ", " + node.id().s + ")"
     elif node.id().b != None:
-      log(self, "NodeID Generation macro for bytestrings has not been implemented.")
+      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
       return ""
     elif node.id().g != None:
-      log(self, "NodeID Generation macro for guids has not been implemented.")
+      logger.debug("NodeID Generation macro for guids has not been implemented.")
       return ""
     else:
       return ""
 
   def substitutePunctuationCharacters(self, input):
     ''' substitutePunctuationCharacters
-    
+
         Replace punctuation characters in input. Part of this class because it is used by
         ua_namespace on occasion.
-        
+
         returns: C-printable string representation of input
     '''
     # No punctuation characters <>!$
@@ -62,7 +65,7 @@ class open62541_MacroHelper():
         substitution = substitution + '_'
 
     return input.translate(string.maketrans(illegal, substitution), illegal)
-  
+
   def getNodeIdDefineString(self, node):
     code = []
     extrNs = node.browseName().split(":")
@@ -75,18 +78,18 @@ class open62541_MacroHelper():
 
     symbolic_name = self.substitutePunctuationCharacters(nodename)
     if symbolic_name != nodename :
-        log(self, "Subsituted characters in browsename for nodeid " + str(node.id().i) + " while generating C-Code ", LOG_LEVEL_WARN)
-    
+        logger.warn("Subsituted characters in browsename for nodeid " + str(node.id().i) + " while generating C-Code ")
+
     if symbolic_name in defined_typealiases:
-      log(self, "Typealias definition of " + str(node.id().i) + " is non unique!", LOG_LEVEL_WARN)
+      logger.warn(self, "Typealias definition of " + str(node.id().i) + " is non unique!")
       extendedN = 1
       while (symbolic_name+"_"+str(extendedN) in defined_typealiases):
-        log(self, "Typealias definition of " + str(node.id().i) + " is non unique!", LOG_LEVEL_WARN)
+        logger.warn("Typealias definition of " + str(node.id().i) + " is non unique!")
         extendedN+=1
-      symbolic_name = symbolic_name+"_"+str(extendedN) 
-      
+      symbolic_name = symbolic_name+"_"+str(extendedN)
+
     defined_typealiases.append(symbolic_name)
-      
+
     code.append("#define UA_NS"  + str(node.id().ns) + "ID_" + symbolic_name.upper() + " " + str(node.id().i))
     return code
 
@@ -96,10 +99,10 @@ class open62541_MacroHelper():
     elif node.id().s != None:
       return "UA_NODEID_STRING("  + str(node.id().ns) + ", " + node.id().s + ")"
     elif node.id().b != None:
-      log(self, "NodeID Generation macro for bytestrings has not been implemented.")
+      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
       return ""
     elif node.id().g != None:
-      log(self, "NodeID Generation macro for guids has not been implemented.")
+      logger.debug("NodeID Generation macro for guids has not been implemented.")
       return ""
     else:
       return ""
@@ -284,20 +287,20 @@ class open62541_MacroHelper():
         code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = " + str(node.id().i) + ";")
       elif node.id().b != None:
         code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_BYTESTRING;")
-        log(self, "ByteString IDs for nodes has not been implemented yet.", LOG_LEVEL_ERROR)
+        logger.error("ByteString IDs for nodes has not been implemented yet.")
         return []
       elif node.id().g != None:
         #<jpfr> the string is sth like { .length = 111, .data = <ptr> }
         #<jpfr> there you _may_ alloc the <ptr> on the heap
         #<jpfr> for the guid, just set it to {.data1 = 111, .data2 = 2222, ....
         code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_GUID;")
-        log(self, "GUIDs for nodes has not been implemented yet.", LOG_LEVEL_ERROR)
+        logger.error(self, "GUIDs for nodes has not been implemented yet.")
         return []
       elif node.id().s != None:
         code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_STRING;")
         code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = UA_STRING_ALLOC(\"" + str(node.id().i) + "\");")
       else:
-        log(self, "Node ID is not numeric, bytestring, guid or string. I do not know how to create c code for that...", LOG_LEVEL_ERROR)
+        logger.error("Node ID is not numeric, bytestring, guid or string. I do not know how to create c code for that...")
         return []
 
     return code

+ 82 - 82
tools/pyUANamespace/open62541_XMLPreprocessor.py

@@ -15,7 +15,7 @@
 ### this program.
 ###
 
-from logger import *
+import logging
 from ua_constants import *
 import tempfile
 import xml.dom.minidom as dom
@@ -25,6 +25,9 @@ from collections import Counter
 
 from ua_namespace import opcua_node_id_t
 
+
+logger = logging.getLogger(__name__)
+
 class preProcessDocument:
   originXML = '' # Original XML passed to the preprocessor
   targetXML = () # tuple of (fileHandle, fileName)
@@ -35,7 +38,7 @@ class preProcessDocument:
   namespaceOrder  = [] # contains xmlns:sX attributed as tuples (int ns, string name)
   namespaceQualifiers = []      # contains all xmlns:XYZ qualifiers that might prefix value aliases (like "<uax:Int32>")
   referencedNamesSpaceUris = [] # contains <NamespaceUris> URI elements
-  
+
   def __init__(self, originXML):
     self.originXML = originXML
     self.targetXML = tempfile.mkstemp(prefix=os.path.basename(originXML)+"_preProcessed-" ,suffix=".xml")
@@ -48,29 +51,29 @@ class preProcessDocument:
     try:
       self.nodeset = dom.parse(originXML)
       if len(self.nodeset.getElementsByTagName("UANodeSet")) == 0 or len(self.nodeset.getElementsByTagName("UANodeSet")) > 1:
-        log(self, "Document " + self.targetXML[1] + " contains no or more then 1 nodeset", LOG_LEVEL_ERROR)
+        logger.error(self, "Document " + self.targetXML[1] + " contains no or more then 1 nodeset", LOG_LEVEL_ERROR)
         self.parseOK   = False
     except:
       self.parseOK   = False
-    log(self, "Adding new document to be preprocessed " + os.path.basename(originXML) + " as " + self.targetXML[1], LOG_LEVEL_DEBUG)
-  
+    logger.debug("Adding new document to be preprocessed " + os.path.basename(originXML) + " as " + self.targetXML[1])
+
   def clean(self):
     #os.close(self.targetXML[0]) Don't -> done to flush() after finalize()
     os.remove(self.targetXML[1])
-  
+
   def getTargetXMLName(self):
     if (self.parseOK):
       return self.targetXML[1]
     return None
-  
+
   def extractNamespaceURIs(self):
     """ extractNamespaceURIs
-        
+
         minidom gobbles up <NamespaceUris></NamespaceUris> elements, without a decent
-        way to reliably access this dom2 <uri></uri> elements (only attribute xmlns= are 
-        accessible using minidom).  We need them for dereferencing though... This 
+        way to reliably access this dom2 <uri></uri> elements (only attribute xmlns= are
+        accessible using minidom).  We need them for dereferencing though... This
         function attempts to do just that.
-        
+
         returns: Nothing
     """
     infile = open(self.originXML)
@@ -86,37 +89,37 @@ class preProcessDocument:
         break
       if foundURIs:
         nsline = nsline + line
-    
+
     if len(nsline) > 0:
       ns = dom.parseString(nsline).getElementsByTagName("NamespaceUris")
       for uri in ns[0].childNodes:
         if uri.nodeType != uri.ELEMENT_NODE:
           continue
         self.referencedNamesSpaceUris.append(uri.firstChild.data)
-      
+
     infile.close()
-    
+
   def analyze(self):
     """ analyze()
-    
+
         analyze will gather information about the nodes and references contained in a XML File
         to facilitate later preprocessing stages that adresss XML dependency issues
-        
+
         returns: No return value
-    """ 
+    """
     nodeIds = []
     ns = self.nodeset.getElementsByTagName("UANodeSet")
-    
+
     # We need to find out what the namespace calls itself and other referenced, as numeric id's are pretty
     # useless sans linked nodes. There is two information sources...
     self.extractNamespaceURIs() # From <URI>...</URI> definitions
-    
+
     for key in ns[0].attributes.keys(): # from xmlns:sX attributes
       if "xmlns:" in key:  # Any key: we will be removing these qualifiers from Values later
         self.namespaceQualifiers.append(key.replace("xmlns:",""))
       if "xmlns:s" in key: # get a numeric nsId and modelname/uri
         self.namespaceOrder.append((int(key.replace("xmlns:s","")), ns[0].getAttribute(key)))
-    
+
     # Get all nodeIds contained in this XML
     for nd in ns[0].childNodes:
       if nd.nodeType != nd.ELEMENT_NODE:
@@ -127,39 +130,39 @@ class preProcessDocument:
         for ref in refs.childNodes:
           if ref.nodeType == ref.ELEMENT_NODE:
             self.referencedNodes.append( (opcua_node_id_t(ref.firstChild.data), ref) )
-    
-    log(self, "Nodes: " + str(len(self.containedNodes)) + " References: " + str(len(self.referencedNodes)), LOG_LEVEL_DEBUG)
-  
+
+    logger.debug("Nodes: " + str(len(self.containedNodes)) + " References: " + str(len(self.referencedNodes)))
+
   def getNamespaceId(self):
     """ namespaceId()
-        
+
         Counts the namespace IDs in all nodes of this XML and picks the most used
         namespace as the numeric identifier of this data model.
-        
+
         returns: Integer ID of the most propable/most used namespace in this XML
     """
     max = 0;
     namespaceIdGuessed = 0;
     idDict = {}
-    
+
     for ndid in self.containedNodes:
       if not idDict.has_key(ndid[0].ns):
         idDict[ndid[0].ns] = 1
       else:
         idDict[ndid[0].ns] = idDict[ndid[0].ns] + 1
-    
+
     for entry in idDict:
       if idDict[entry] > max:
         max = idDict[entry]
         namespaceIdGuessed = entry
-    log(self, "XML Contents are propably in namespace " + str(entry) + " (used by " + str(idDict[entry]) + " Nodes)", LOG_LEVEL_DEBUG)
+    logger.debug("XML Contents are propably in namespace " + str(entry) + " (used by " + str(idDict[entry]) + " Nodes)")
     return namespaceIdGuessed
-  
+
   def getReferencedNamespaceUri(self, nsId):
     """ getReferencedNamespaceUri
-    
+
         returns an URL that hopefully corresponds to the nsId that was used to reference this model
-        
+
         return: URI string corresponding to nsId
     """
     # Might be the more reliable method: Get the URI from the xmlns attributes (they have numers)
@@ -167,22 +170,22 @@ class preProcessDocument:
       for el in self.namespaceOrder:
         if el[0] == nsId:
           return el[1]
-    
-    # Fallback: 
+
+    # Fallback:
     #  Some models do not have xmlns:sX attributes, but still <URI>s (usually when they only reference NS0)
     if len(self.referencedNamesSpaceUris) > 0  and len(self.referencedNamesSpaceUris) >= nsId-1:
       return self.referencedNamesSpaceUris[nsId-1]
-    
+
     #Nope, not found.
     return ""
-  
+
   def getNamespaceDependencies(self):
     deps = []
     for ndid in self.referencedNodes:
       if not ndid[0].ns in deps:
         deps.append(ndid[0].ns)
     return deps
-    
+
   def finalize(self):
     outfile = self.targetXML[0]
     outline = self.nodeset.toxml()
@@ -191,29 +194,29 @@ class preProcessDocument:
       outline = outline.replace(rq.decode('UTF-8'), "")
     os.write(outfile, outline.encode('UTF-8'))
     os.close(outfile)
-    
+
   def reassignReferencedNamespaceId(self, currentNsId, newNsId):
     """ reassignReferencedNamespaceId
-        
+
         Iterates over all references in this document, find references to currentNsId and changes them to newNsId.
         NodeIds themselves are not altered.
-        
+
         returns: nothing
-    """ 
+    """
     for refNd in self.referencedNodes:
       if refNd[0].ns == currentNsId:
         refNd[1].firstChild.data = refNd[1].firstChild.data.replace("ns="+str(currentNsId), "ns="+str(newNsId))
         refNd[0].ns = newNsId
         refNd[0].toString()
-  
+
   def reassignNamespaceId(self, currentNsId, newNsId):
     """ reassignNamespaceId
-        
+
         Iterates over all nodes in this document, find those in namespace currentNsId and changes them to newNsId.
-        
+
         returns: nothing
-    """ 
-    log(self, "Migrating nodes /w ns index " + str(currentNsId) + " to " + str(newNsId), LOG_LEVEL_DEBUG)
+    """
+    logger.debug("Migrating nodes /w ns index " + str(currentNsId) + " to " + str(newNsId))
     for nd in self.containedNodes:
       if nd[0].ns == currentNsId:
         # In our own document, update any references to this node
@@ -225,33 +228,33 @@ class preProcessDocument:
         nd[1].setAttribute(u'NodeId', nd[1].getAttribute(u'NodeId').replace("ns="+str(currentNsId), "ns="+str(newNsId)))
         nd[0].ns = newNsId
         nd[0].toString()
-  
+
 class open62541_XMLPreprocessor:
   preProcDocuments = []
-  
+
   def __init__(self):
       self.preProcDocuments = []
-      
+
   def addDocument(self, documentPath):
     self.preProcDocuments.append(preProcessDocument(documentPath))
-    
+
   def removePreprocessedFiles(self):
     for doc in self.preProcDocuments:
       doc.clean()
-  
+
   def getPreProcessedFiles(self):
     files = []
     for doc in self.preProcDocuments:
       if (doc.parseOK):
         files.append(doc.getTargetXMLName())
     return files
-  
+
   def testModelCongruencyAgainstReferences(self, doc, refs):
     """ testModelCongruencyAgainstReferences
-    
+
         Counts how many of the nodes referencef in refs can be found in the model
         doc.
-        
+
         returns: double corresponding to the percentage of hits
     """
     sspace = len(refs)
@@ -265,7 +268,7 @@ class open62541_XMLPreprocessor:
           found = found + 1
           break
     return float(found)/float(sspace)
-    
+
   def preprocess_assignUniqueNsIds(self):
     nsdep  = []
     docLst = []
@@ -276,7 +279,7 @@ class open62541_XMLPreprocessor:
         docLst.append(doc)
     for doc in docLst:
       self.preProcDocuments.remove(doc)
-    
+
     # Reassign namespace id's to be in ascending order
     nsidx = 1 # next namespace id to assign on collision (first one will be "2")
     for doc in self.preProcDocuments:
@@ -284,14 +287,14 @@ class open62541_XMLPreprocessor:
       nsid = doc.getNamespaceId()
       doc.reassignNamespaceId(nsid, nsidx)
       docLst.append(doc)
-      log(self, "Document " + doc.originXML + " is now namespace " + str(nsidx), LOG_LEVEL_INFO)
+      logger.info("Document " + doc.originXML + " is now namespace " + str(nsidx))
     self.preProcDocuments = docLst
-  
+
   def getUsedNamespaceArrayNames(self):
     """ getUsedNamespaceArrayNames
-    
+
         Returns the XML xmlns:s1 or <URI>[0] of each XML document (if contained/possible)
-        
+
         returns: dict of int:nsId -> string:url
     """
     nsName = {}
@@ -301,10 +304,10 @@ class open62541_XMLPreprocessor:
         uri = "http://modeluri.not/retrievable/from/xml"
       nsName[doc.getNamespaceId()] = doc.getReferencedNamespaceUri(1)
     return nsName
-      
-  def preprocess_linkDependantModels(self):    
+
+  def preprocess_linkDependantModels(self):
     revertToStochastic = [] # (doc, int id), where id was not resolvable using model URIs
-    
+
     # Attemp to identify the model relations by using model URIs in xmlns:sX or <URI> contents
     for doc in self.preProcDocuments:
       nsid = doc.getNamespaceId()
@@ -313,10 +316,10 @@ class open62541_XMLPreprocessor:
         if d != nsid and d != 0:
           # Attempt to identify the namespace URI this d referes to...
           nsUri = doc.getReferencedNamespaceUri(d) # FIXME: This could actually fail and return ""!
-          log(self, "Need a namespace referenced as " + str(d) + ". Which hopefully is " + nsUri, LOG_LEVEL_INFO)
+          logger.info("Need a namespace referenced as " + str(d) + ". Which hopefully is " + nsUri)
           targetDoc = None
           for tgt in self.preProcDocuments:
-            # That model, whose URI is known but its current id is not, will 
+            # That model, whose URI is known but its current id is not, will
             #   refer have referred to itself as "1"
             if tgt.getReferencedNamespaceUri(1) == nsUri:
               targetDoc = tgt
@@ -326,11 +329,11 @@ class open62541_XMLPreprocessor:
             doc.reassignReferencedNamespaceId(d, targetDoc.getNamespaceId())
             continue
           else:
-            revertToStochastic.append((doc, d)) 
-            log(self, "Failed to reliably identify which XML/Model " + os.path.basename(doc.originXML) + " calls ns=" +str(d), LOG_LEVEL_WARN)
-    
+            revertToStochastic.append((doc, d))
+            logger.warn("Failed to reliably identify which XML/Model " + os.path.basename(doc.originXML) + " calls ns=" +str(d))
+
     for (doc, d) in revertToStochastic:
-      log(self, "Attempting to find stochastic match for target namespace ns=" + str(d) + " of " + os.path.basename(doc.originXML), LOG_LEVEL_WARN)
+      logger.warn("Attempting to find stochastic match for target namespace ns=" + str(d) + " of " + os.path.basename(doc.originXML))
       # Copy all references to the given namespace
       refs = []
       matches = [] # list of (match%, targetDoc) to pick from later
@@ -354,37 +357,34 @@ class open62541_XMLPreprocessor:
         if m[0] > best[0]:
           best = m
       if best[1] != None:
-        log(self, "Best match (" + str(best[1]*100) + "%) for what " + os.path.basename(doc.originXML) + " refers to as ns="+str(d)+" was " + os.path.basename(best[1].originXML), LOG_LEVEL_WARN)
+        logger.warn("Best match (" + str(best[1]*100) + "%) for what " + os.path.basename(doc.originXML) + " refers to as ns="+str(d)+" was " + os.path.basename(best[1].originXML))
         doc.reassignReferencedNamespaceId(d, best[1].getNamespaceId())
-      else: 
-        log(self, "Failed to find a match for what " +  os.path.basename(doc.originXML) + " refers to as ns=" + str(d) ,LOG_LEVEL_ERROR )
-      
+      else:
+        logger.error("Failed to find a match for what " +  os.path.basename(doc.originXML) + " refers to as ns=" + str(d))
+
   def preprocessAll(self):
     ##
     ## First: Gather statistics about the namespaces:
     for doc in self.preProcDocuments:
       doc.analyze()
-    
+
     # Preprocess step: Remove XML specific Naming scheme ("uax:")
     # FIXME: Not implemented
-    
+
     ##
     ## Preprocess step: Check namespace ID multiplicity and reassign IDs if necessary
     ##
     self.preprocess_assignUniqueNsIds()
     self.preprocess_linkDependantModels()
-    
-    
-    ##  
+
+
+    ##
     ## Prep step: prevent any XML from using namespace 1 (reserved for instances)
     ## FIXME: Not implemented
-    
+
     ##
     ## Final: Write modified XML tmp files
     for doc in self.preProcDocuments:
       doc.finalize()
-    
-    return True
-      
-  
 
+    return True

+ 140 - 138
tools/pyUANamespace/ua_builtin_types.py

@@ -19,10 +19,12 @@
 import sys
 import xml.dom.minidom as dom
 from ua_constants import *
-from logger import *
+import logging
 from time import strftime, strptime
 from open62541_MacroHelper import open62541_MacroHelper
 
+logger = logging.getLogger(__name__)
+
 def getNextElementNode(xmlvalue):
   if xmlvalue == None:
     return None
@@ -60,7 +62,7 @@ class opcua_value_t():
                        'qualifiedname', 'expandednodeid', 'xmlelement']
     self.dataType = None
     self.encodingRule = []
-  
+
   def getValueFieldByAlias(self, fieldname):
     if not isinstance(self.value, list):
       return None
@@ -70,7 +72,7 @@ class opcua_value_t():
       if val.alias() == fieldname:
 	return val.value
     return None
-    
+
   def setEncodingRule(self, encoding):
     self.encodingRule = encoding
 
@@ -161,19 +163,19 @@ class opcua_value_t():
       t = opcua_BuiltinType_xmlelement_t(self.parent)
       t.setEncodingRule(encodingRule)
     else:
-      log(self, "No class representing stringName " + stringName + " was found. Cannot create builtinType.")
+      logger.debug("No class representing stringName " + stringName + " was found. Cannot create builtinType.")
       return None
     return t
 
   def parseXML(self, xmlvalue):
-    log(self, "parsing xmlvalue for " + self.parent.browseName() + " (" + str(self.parent.id()) + ") according to " + str(self.parent.dataType().target().getEncoding()))
+    logger.debug("parsing xmlvalue for " + self.parent.browseName() + " (" + str(self.parent.id()) + ") according to " + str(self.parent.dataType().target().getEncoding()))
 
     if not "value" in xmlvalue.tagName.lower():
-      log(self, "Expected <Value> , but found " + xmlvalue.tagName + " instead. Value will not be parsed.", LOG_LEVEL_ERROR)
+      logger.error("Expected <Value> , but found " + xmlvalue.tagName + " instead. Value will not be parsed.")
       return
 
     if len(xmlvalue.childNodes) == 0:
-      log(self, "Expected childnodes for value, but none where found... Value will not be parsed.", LOG_LEVEL_ERROR)
+      logger.error("Expected childnodes for value, but none where found... Value will not be parsed.")
       return
 
     for n in xmlvalue.childNodes:
@@ -190,7 +192,7 @@ class opcua_value_t():
     else:
       self.value = [self.__parseXMLSingleValue(xmlvalue)]
 
-    log(self, "Parsed Value: " + str(self.value))
+    logger.debug( "Parsed Value: " + str(self.value))
 
   def __parseXMLSingleValue(self, xmlvalue, alias=None, encodingPart=None):
     # Parse an encoding list such as enc = [[Int32], ['Duration', ['DateTime']]],
@@ -216,7 +218,7 @@ class opcua_value_t():
         # 0: 'BuiltinType'
         if alias != None:
           if not xmlvalue.tagName == alias:
-            log(self, "Expected XML element with tag " + alias + " but found " + xmlvalue.tagName + " instead", LOG_LEVEL_ERROR)
+            logger.error("Expected XML element with tag " + alias + " but found " + xmlvalue.tagName + " instead")
             return None
           else:
             t = self.getTypeByString(enc[0], enc)
@@ -225,7 +227,7 @@ class opcua_value_t():
             return t
         else:
           if not self.isBuiltinByString(xmlvalue.tagName):
-            log(self, "Expected XML describing builtin type " + enc[0] + " but found " + xmlvalue.tagName + " instead", LOG_LEVEL_ERROR)
+            logger.error("Expected XML describing builtin type " + enc[0] + " but found " + xmlvalue.tagName + " instead")
           else:
             t = self.getTypeByString(enc[0], enc)
             t.parseXML(xmlvalue)
@@ -253,29 +255,29 @@ class opcua_value_t():
       #        Consider moving this ExtensionObject specific parsing into the
       #        builtin type and only determining the multipart type at this stage.
       if not xmlvalue.tagName == "ExtensionObject":
-        log(self, "Expected XML tag <ExtensionObject> for multipart type, but found " + xmlvalue.tagName + " instead.", LOG_LEVEL_ERROR)
+        logger.error("Expected XML tag <ExtensionObject> for multipart type, but found " + xmlvalue.tagName + " instead.")
         return None
 
       extobj = opcua_BuiltinType_extensionObject_t(self.parent)
       extobj.setEncodingRule(enc)
       etype = xmlvalue.getElementsByTagName("TypeId")
       if len(etype) == 0:
-        log(self, "Did not find <TypeId> for ExtensionObject", LOG_LEVEL_ERROR)
+        logger.error("Did not find <TypeId> for ExtensionObject")
         return None
       etype = etype[0].getElementsByTagName("Identifier")
       if len(etype) == 0:
-        log(self, "Did not find <Identifier> for ExtensionObject", LOG_LEVEL_ERROR)
+        logger.error("Did not find <Identifier> for ExtensionObject")
         return None
       etype = self.parent.getNamespace().getNodeByIDString(etype[0].firstChild.data)
       if etype == None:
-        log(self, "Identifier Node not found in namespace" , LOG_LEVEL_ERROR)
+        logger.error("Identifier Node not found in namespace" )
         return None
 
       extobj.typeId(etype)
 
       ebody = xmlvalue.getElementsByTagName("Body")
       if len(ebody) == 0:
-        log(self, "Did not find <Body> for ExtensionObject", LOG_LEVEL_ERROR)
+        logger.error("Did not find <Body> for ExtensionObject")
         return None
       ebody = ebody[0]
 
@@ -284,11 +286,11 @@ class opcua_value_t():
       if not ebodypart.nodeType == ebodypart.ELEMENT_NODE:
         ebodypart = getNextElementNode(ebodypart)
       if ebodypart == None:
-        log(self, "Expected ExtensionObject to hold a variable of type " + str(self.parent.dataType().target().browseName()) + " but found nothing.", LOG_LEVEL_ERROR)
+        logger.error("Expected ExtensionObject to hold a variable of type " + str(self.parent.dataType().target().browseName()) + " but found nothing.")
         return None
 
       if not ebodypart.tagName == self.parent.dataType().target().browseName():
-        log(self, "Expected ExtensionObject to hold a variable of type " + str(self.parent.dataType().target().browseName()) + " but found " + str(ebodypart.tagName) + " instead.", LOG_LEVEL_ERROR)
+        logger.error("Expected ExtensionObject to hold a variable of type " + str(self.parent.dataType().target().browseName()) + " but found " + str(ebodypart.tagName) + " instead.")
         return None
       extobj.alias(ebodypart.tagName)
 
@@ -296,7 +298,7 @@ class opcua_value_t():
       if not ebodypart.nodeType == ebodypart.ELEMENT_NODE:
         ebodypart = getNextElementNode(ebodypart)
       if ebodypart == None:
-        log(self, "Description of dataType " + str(self.parent.dataType().target().browseName()) + " in ExtensionObject is empty/invalid.", LOG_LEVEL_ERROR)
+        logger.error("Description of dataType " + str(self.parent.dataType().target().browseName()) + " in ExtensionObject is empty/invalid.")
         return None
 
       extobj.value = []
@@ -304,7 +306,7 @@ class opcua_value_t():
         if not ebodypart == None:
           extobj.value.append(extobj.__parseXMLSingleValue(ebodypart, alias=None, encodingPart=e))
         else:
-          log(self, "Expected encoding " + str(e) + " but found none in body.", LOG_LEVEL_ERROR)
+          logger.error("Expected encoding " + str(e) + " but found none in body.")
         ebodypart = getNextElementNode(ebodypart)
       return extobj
 
@@ -348,27 +350,27 @@ class opcua_value_t():
       return code
     if not isinstance(self.value[0], opcua_value_t):
       return code
-  
+
     if self.parent.valueRank() != -1 and (self.parent.valueRank() >=0 or (len(self.value) > 1 and (self.parent.valueRank() != -2 or self.parent.valueRank() != -3))):
       # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
       if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_GUID:
-        log(self, "Don't know how to print array of GUID in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print array of GUID in node " + str(self.parent.id()))
       elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DATETIME:
-        log(self, "Don't know how to print array of DateTime in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print array of DateTime in node " + str(self.parent.id()))
       elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DIAGNOSTICINFO:
-        log(self, "Don't know how to print array of DiagnosticInfo in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print array of DiagnosticInfo in node " + str(self.parent.id()))
       elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_STATUSCODE:
-        log(self, "Don't know how to print array of StatusCode in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print array of StatusCode in node " + str(self.parent.id()))
       else:
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           for v in self.value:
-            log(self, "Building extObj array index " + str(self.value.index(v)))
+            logger.debug("Building extObj array index " + str(self.value.index(v)))
             code = code + v.printOpen62541CCode_SubType_build(arrayIndex=self.value.index(v))
         #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
         code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + "[" + str(len(self.value)) + "];")
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           for v in self.value:
-            log(self, "Printing extObj array index " + str(self.value.index(v)))
+            logger.debug("Printing extObj array index " + str(self.value.index(v)))
             code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType(asIndirect=False) + ";")
             code.append("UA_free(" + v.printOpen62541CCode_SubType() + ");")
         else:
@@ -379,13 +381,13 @@ class opcua_value_t():
     else:
       # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
       if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_GUID:
-        log(self, "Don't know how to print scalar GUID in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print scalar GUID in node " + str(self.parent.id()))
       elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DATETIME:
-        log(self, "Don't know how to print scalar DateTime in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print scalar DateTime in node " + str(self.parent.id()))
       elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_DIAGNOSTICINFO:
-        log(self, "Don't know how to print scalar DiagnosticInfo in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print scalar DiagnosticInfo in node " + str(self.parent.id()))
       elif self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_STATUSCODE:
-        log(self, "Don't know how to print scalar StatusCode in node " + str(self.parent.id()), LOG_LEVEL_WARN)
+        logger.warn("Don't know how to print scalar StatusCode in node " + str(self.parent.id()))
       else:
         # The following strategy applies to all other types, in particular strings and numerics.
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
@@ -433,16 +435,16 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
     code = [""]
     codegen = open62541_MacroHelper();
 
-    log(self, "Building extensionObject for " + str(self.parent.id()))
-    log(self, "Value    " + str(self.value))
-    log(self, "Encoding " + str(self.getEncodingRule()))
+    logger.debug("Building extensionObject for " + str(self.parent.id()))
+    logger.debug("Value    " + str(self.value))
+    logger.debug("Encoding " + str(self.getEncodingRule()))
 
     self.setCodeInstanceName(recursionDepth, arrayIndex)
     # If there are any ExtensionObjects instide this ExtensionObject, we need to
     # generate one-time-structs for them too before we can proceed;
     for subv in self.value:
       if isinstance(subv, list):
-        log(self, "ExtensionObject contains an ExtensionObject, which is currently not encodable!", LOG_LEVEL_ERR)
+        logger.debug("ExtensionObject contains an ExtensionObject, which is currently not encodable!", LOG_LEVEL_ERR)
 
     code.append("struct {")
     for field in self.getEncodingRule():
@@ -463,7 +465,7 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
     for subv in self.value:
       encField = self.getEncodingRule()[encFieldIdx]
       encFieldIdx = encFieldIdx + 1;
-      log(self, "Encoding of field " + subv.alias() + " is " + str(subv.getEncodingRule()) + "defined by " + str(encField))
+      logger.debug("Encoding of field " + subv.alias() + " is " + str(subv.getEncodingRule()) + "defined by " + str(encField))
       # Check if this is an array
       if encField[2] == 0:
         code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + " = " + subv.printOpen62541CCode_SubType(asIndirect=False) + ";")
@@ -472,10 +474,10 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
           # this is an array
           code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "Size = " + str(len(subv)) + ";")
           code.append(self.getCodeInstanceName()+"_struct."+subv.alias()+" = (UA_" + subv.stringRepresentation + " *) UA_malloc(sizeof(UA_" + subv.stringRepresentation + ")*"+ str(len(subv))+");")
-          log(self, "Encoding included array of " + str(len(subv)) + " values.")
+          logger.debug("Encoding included array of " + str(len(subv)) + " values.")
           for subvidx in range(0,len(subv)):
             subvv = subv[subvidx]
-            log(self, "  " + str(subvix) + " " + str(subvv))
+            logger.debug("  " + str(subvix) + " " + str(subvv))
             code.append(self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + "] = " + subvv.printOpen62541CCode_SubType(asIndirect=True) + ";")
           code.append("}")
         else:
@@ -537,32 +539,32 @@ class opcua_BuiltinType_localizedtext_t(opcua_value_t):
     #        <LocalizedText> or </AliasName>
     #
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     if xmlvalue.firstChild == None:
       if self.alias() != None:
-        log(self, "Neither locale nor text in XML description field " + self.alias() + ". Setting to default ['en_US','']")
+        logger.debug("Neither locale nor text in XML description field " + self.alias() + ". Setting to default ['en_US','']")
       else:
-        log(self, "Neither locale nor text in XML description. Setting to default ['en_US','']")
+        logger.debug("Neither locale nor text in XML description. Setting to default ['en_US','']")
       self.value = ['en_US','']
       return
 
     self.value = []
     tmp = xmlvalue.getElementsByTagName("Locale")
     if len(tmp) == 0:
-      log(self, "Did not find a locale. Setting to en_US per default.", LOG_LEVEL_WARN)
+      logger.warn("Did not find a locale. Setting to en_US per default.")
       self.value.append('en_US')
     else:
       if tmp[0].firstChild == None:
-        log(self, "Locale tag without contents. Setting to en_US per default.", LOG_LEVEL_WARN)
+        logger.warn("Locale tag without contents. Setting to en_US per default.")
         self.value.append('en_US')
       else:
         self.value.append(tmp[0].firstChild.data)
@@ -574,11 +576,11 @@ class opcua_BuiltinType_localizedtext_t(opcua_value_t):
 
     tmp = xmlvalue.getElementsByTagName("Text")
     if len(tmp) == 0:
-      log(self, "Did not find a Text. Setting to empty string per default.", LOG_LEVEL_WARN)
+      logger.warn("Did not find a Text. Setting to empty string per default.")
       self.value.append('')
     else:
       if tmp[0].firstChild == None:
-        log(self, "Text tag without content. Setting to empty string per default.", LOG_LEVEL_WARN)
+        logger.warn("Text tag without content. Setting to empty string per default.")
         self.value.append('')
       else:
         self.value.append(tmp[0].firstChild.data)
@@ -599,10 +601,10 @@ class opcua_BuiltinType_expandednodeid_t(opcua_value_t):
 
   def parseXML(self, xmlvalue):
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
-    log(self, "Not implemented", LOG_LEVEL_ERR)
+    logger.debug("Not implemented", LOG_LEVEL_ERR)
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     #FIXME! This one is definetely broken!
@@ -623,19 +625,19 @@ class opcua_BuiltinType_nodeid_t(opcua_value_t):
     #           </Identifier>
     #        </NodeId> or </Alias>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <NodeId />
     if xmlvalue.firstChild == None :
-      log(self, "No value is given, which is illegal for Node Types...", LOG_LEVEL_ERROR)
+      logger.error("No value is given, which is illegal for Node Types...")
       self.value = None
     else:
       # Check if there is an <Identifier> tag
@@ -643,7 +645,7 @@ class opcua_BuiltinType_nodeid_t(opcua_value_t):
         xmlvalue = xmlvalue.getElementsByTagName("Identifier")[0]
       self.value = self.parent.getNamespace().getNodeByIDString(unicode(xmlvalue.firstChild.data))
       if self.value == None:
-        log(self, "Node with id " + str(unicode(xmlvalue.firstChild.data)) + " was not found in namespace.", LOG_LEVEL_ERROR)
+        logger.error("Node with id " + str(unicode(xmlvalue.firstChild.data)) + " was not found in namespace.")
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     if self.value == None:
@@ -654,10 +656,10 @@ class opcua_BuiltinType_nodeid_t(opcua_value_t):
     elif nodeId.s != None:
       return "UA_NODEID_STRING("  + str(nodeId.ns) + ", " + str(nodeId.s) + ")"
     elif nodeId.b != None:
-      log(self, "NodeID Generation macro for bytestrings has not been implemented.")
+      logger.debug("NodeID Generation macro for bytestrings has not been implemented.")
       return "UA_NODEID_NUMERIC(0,0)"
     elif nodeId.g != None:
-      log(self, "NodeID Generation macro for guids has not been implemented.")
+      logger.debug("NodeID Generation macro for guids has not been implemented.")
       return "UA_NODEID_NUMERIC(0,0)"
     return "UA_NODEID_NUMERIC(0,0)"
 
@@ -673,19 +675,19 @@ class opcua_BuiltinType_datetime_t(opcua_value_t):
     #        2013-08-13T21:00:05.0000L
     #        </DateTime> or </AliasName>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <DateTime /> by setting the value to a default
     if xmlvalue.firstChild == None :
-      log(self, "No value is given. Setting to default now()")
+      logger.debug("No value is given. Setting to default now()")
       self.value = strptime(strftime("%Y-%m-%dT%H:%M%S"), "%Y-%m-%dT%H:%M%S")
     else:
       timestr = unicode(xmlvalue.firstChild.data)
@@ -699,7 +701,7 @@ class opcua_BuiltinType_datetime_t(opcua_value_t):
       try:
         self.value = strptime(timestr, "%Y-%m-%dT%H:%M:%S")
       except:
-        log(self, "Timestring format is illegible. Expected 2001-01-30T21:22:23, but got " + timestr + " instead. Time will be defaultet to now()", LOG_LEVEL_ERROR)
+        logger.error("Timestring format is illegible. Expected 2001-01-30T21:22:23, but got " + timestr + " instead. Time will be defaultet to now()")
         self.value = strptime(strftime("%Y-%m-%dT%H:%M%S"), "%Y-%m-%dT%H:%M%S")
 
 class opcua_BuiltinType_qualifiedname_t(opcua_value_t):
@@ -715,19 +717,19 @@ class opcua_BuiltinType_qualifiedname_t(opcua_value_t):
     #           <Name>SomeString<Name>                # Speculation: Manditory if NamespaceIndex is given, omitted otherwise?
     #        </QualifiedName> or </AliasName>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Qalified /> by setting the value to a default
     if xmlvalue.firstChild == None :
-      log(self, "No value is given. Setting to default empty string in ns=0: [0, '']")
+      logger.debug("No value is given. Setting to default empty string in ns=0: [0, '']")
       self.value = [0, '']
     else:
       # Is a namespace index passed?
@@ -737,10 +739,10 @@ class opcua_BuiltinType_qualifiedname_t(opcua_value_t):
         if len(xmlvalue.getElementsByTagName("Name")) != 0:
           self.value.append(xmlvalue.getElementsByTagName("Name")[0].firstChild.data)
         else:
-          log(self, "No name is specified, will default to empty string")
+          logger.debug("No name is specified, will default to empty string")
           self.value.append('')
       else:
-        log(self, "No namespace is specified, will default to 0")
+        logger.debug("No namespace is specified, will default to 0")
         self.value = [0]
         self.value.append(unicode(xmlvalue.firstChild.data))
 
@@ -757,9 +759,9 @@ class opcua_BuiltinType_statuscode_t(opcua_value_t):
 
   def parseXML(self, xmlvalue):
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
-    log(self, "Not implemented", LOG_LEVEL_WARN)
+    logger.warn("Not implemented")
 
 class opcua_BuiltinType_diagnosticinfo_t(opcua_value_t):
   def setStringReprentation(self):
@@ -770,9 +772,9 @@ class opcua_BuiltinType_diagnosticinfo_t(opcua_value_t):
 
   def parseXML(self, xmlvalue):
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
-    log(self, "Not implemented", LOG_LEVEL_WARN)
+    logger.warn("Not implemented")
 
 class opcua_BuiltinType_guid_t(opcua_value_t):
   def setStringReprentation(self):
@@ -783,19 +785,19 @@ class opcua_BuiltinType_guid_t(opcua_value_t):
 
   def parseXML(self, xmlvalue):
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Guid /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = [0,0,0,0]
     else:
       self.value = unicode(xmlvalue.firstChild.data)
@@ -808,11 +810,11 @@ class opcua_BuiltinType_guid_t(opcua_value_t):
         try:
           tmp.append(int("0x"+g, 16))
         except:
-          log(self, "Invalid formatting of Guid. Expected {01234567-89AB-CDEF-ABCD-0123456789AB}, got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+          logger.error("Invalid formatting of Guid. Expected {01234567-89AB-CDEF-ABCD-0123456789AB}, got " + unicode(xmlvalue.firstChild.data))
           self.value = [0,0,0,0,0]
           ok = False
       if len(tmp) != 5:
-        log(self, "Invalid formatting of Guid. Expected {01234567-89AB-CDEF-ABCD-0123456789AB}, got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Invalid formatting of Guid. Expected {01234567-89AB-CDEF-ABCD-0123456789AB}, got " + unicode(xmlvalue.firstChild.data))
         self.value = [0,0,0,0]
         ok = False
       self.value = tmp
@@ -828,19 +830,19 @@ class opcua_BuiltinType_boolean_t(opcua_value_t):
     # Expect <Boolean>value</Boolean> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Boolean /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = "false"
     else:
       if "false" in unicode(xmlvalue.firstChild.data).lower():
@@ -862,25 +864,25 @@ class opcua_BuiltinType_byte_t(opcua_value_t):
     # Expect <Byte>value</Byte> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Byte /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -896,25 +898,25 @@ class opcua_BuiltinType_sbyte_t(opcua_value_t):
     # Expect <SByte>value</SByte> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <SByte /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -930,25 +932,25 @@ class opcua_BuiltinType_int16_t(opcua_value_t):
     # Expect <Int16>value</Int16> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Int16 /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -964,25 +966,25 @@ class opcua_BuiltinType_uint16_t(opcua_value_t):
     # Expect <UInt16>value</UInt16> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <UInt16 /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -998,25 +1000,25 @@ class opcua_BuiltinType_int32_t(opcua_value_t):
     # Expect <Int32>value</Int32> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Int32 /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -1032,25 +1034,25 @@ class opcua_BuiltinType_uint32_t(opcua_value_t):
     # Expect <UInt32>value</UInt32> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <UInt32 /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -1067,20 +1069,20 @@ class opcua_BuiltinType_int64_t(opcua_value_t):
     #        <Aliasname>value</Aliasname>
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Int64 /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -1096,25 +1098,25 @@ class opcua_BuiltinType_uint64_t(opcua_value_t):
     # Expect <UInt16>value</UInt16> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <UInt64 /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0
     else:
       try:
         self.value = int(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -1130,25 +1132,25 @@ class opcua_BuiltinType_float_t(opcua_value_t):
     # Expect <Float>value</Float> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Float /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0.0
     else:
       try:
         self.value = float(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -1164,25 +1166,25 @@ class opcua_BuiltinType_double_t(opcua_value_t):
     # Expect <Double>value</Double> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <Double /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = 0.0
     else:
       try:
         self.value = float(unicode(xmlvalue.firstChild.data))
       except:
-        log(self, "Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data), LOG_LEVEL_ERROR)
+        logger.error("Error parsing integer. Expected " + self.stringRepresentation + " but got " + unicode(xmlvalue.firstChild.data))
 
   def printOpen62541CCode_SubType(self, asIndirect=True):
     return "(UA_" + self.stringRepresentation + ") " + str(self.value)
@@ -1203,19 +1205,19 @@ class opcua_BuiltinType_string_t(opcua_value_t):
     # Expect <String>value</String> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <String /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = ""
     else:
       self.value = str(unicode(xmlvalue.firstChild.data))
@@ -1246,19 +1248,19 @@ class opcua_BuiltinType_bytestring_t(opcua_value_t):
     # Expect <ByteString>value</ByteString> or
     #        <Aliasname>value</Aliasname>
     if xmlvalue == None or xmlvalue.nodeType != xmlvalue.ELEMENT_NODE:
-      log(self, "Expected XML Element, but got junk...", LOG_LEVEL_ERROR)
+      logger.error("Expected XML Element, but got junk...")
       return
 
     if self.alias() != None:
       if not self.alias() == xmlvalue.tagName:
-        log(self, "Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected an aliased XML field called " + self.alias() + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
     else:
       if not self.stringRepresentation == xmlvalue.tagName:
-        log(self, "Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.", LOG_LEVEL_WARN)
+        logger.warn("Expected XML field " + self.stringRepresentation + " but got " + xmlvalue.tagName + " instead. This is a parsing error of opcua_value_t.__parseXMLSingleValue(), will try to continue anyway.")
 
     # Catch XML <ByteString /> by setting the value to a default
     if xmlvalue.firstChild == None:
-      log(self, "No value is given. Setting to default 0")
+      logger.debug("No value is given. Setting to default 0")
       self.value = ""
     else:
       self.value = str(unicode(xmlvalue.firstChild.data))
@@ -1268,7 +1270,7 @@ class opcua_BuiltinType_bytestring_t(opcua_value_t):
       for line in self.value:
         bs = bs + str(line).replace("\n","");
       outs = bs
-      log(self, "Encoded Bytestring: " + outs, LOG_LEVEL_DEBUG)
+      logger.debug("Encoded Bytestring: " + outs)
 #      bs = bs.decode('base64')
 #      outs = ""
 #      for s in bs:

+ 85 - 84
tools/pyUANamespace/ua_namespace.py

@@ -21,12 +21,15 @@ import sys
 from time import struct_time, strftime, strptime, mktime
 from struct import pack as structpack
 
-from logger import *;
+import logging
 from ua_builtin_types import *;
 from ua_node_types import *;
 from ua_constants import *;
 from open62541_MacroHelper import open62541_MacroHelper
 
+
+logger = logging.getLogger(__name__)
+
 def getNextElementNode(xmlvalue):
   if xmlvalue == None:
     return None
@@ -59,7 +62,7 @@ class opcua_namespace():
   name = ""
   knownNodeTypes = ""
   namespaceIdentifiers = {} # list of 'int':'string' giving different namespace an array-mapable name
-  
+
   def __init__(self, name):
     self.nodes = []
     self.knownNodeTypes = ['variable', 'object', 'method', 'referencetype', \
@@ -73,7 +76,7 @@ class opcua_namespace():
 
   def addNamespace(self, numericId, stringURL):
     self.namespaceIdentifiers[numericId] = stringURL
-    
+
   def linkLater(self, pointer):
     """ Called by nodes or references who have parsed an XML reference to a
         node represented by a string.
@@ -112,7 +115,7 @@ class opcua_namespace():
         dereferencing during pointer linkage (see linkOpenPointer()).
     """
     if not xmlelement.tagName == "Aliases":
-      log(self, "XMLElement passed is not an Aliaslist", LOG_LEVEL_ERROR)
+      logger.error("XMLElement passed is not an Aliaslist")
       return
     for al in xmlelement.childNodes:
       if al.nodeType == al.ELEMENT_NODE:
@@ -124,10 +127,10 @@ class opcua_namespace():
             aliasnd = al.firstChild.data
           if not aliasst in self.aliases:
             self.aliases[aliasst] = aliasnd
-            log(self, "Added new alias \"" + str(aliasst) + "\" == \"" + str(aliasnd) + "\"")
+            logger.debug("Added new alias \"" + str(aliasst) + "\" == \"" + str(aliasnd) + "\"")
           else:
             if self.aliases[aliasst] != aliasnd:
-              log(self, "Alias definitions for " + aliasst + " differ. Have " + self.aliases[aliasst] + " but XML defines " + aliasnd + ". Keeping current definition.", LOG_LEVEL_ERROR)
+              logger.error("Alias definitions for " + aliasst + " differ. Have " + self.aliases[aliasst] + " but XML defines " + aliasnd + ". Keeping current definition.")
 
   def getNodeByBrowseName(self, idstring):
     """ Returns the first node in the nodelist whose browseName matches idstring.
@@ -137,7 +140,7 @@ class opcua_namespace():
       if idstring==str(n.browseName()):
         matches.append(n)
     if len(matches) > 1:
-      log(self, "Found multiple nodes with same ID!?", LOG_LEVEL_ERROR)
+      logger.error("Found multiple nodes with same ID!?")
     if len(matches) == 0:
       return None
     else:
@@ -152,7 +155,7 @@ class opcua_namespace():
       if idstring==str(n.id()):
         matches.append(n)
     if len(matches) > 1:
-      log(self, "Found multiple nodes with same ID!?", LOG_LEVEL_ERROR)
+      logger.error("Found multiple nodes with same ID!?")
     if len(matches) == 0:
       return None
     else:
@@ -187,10 +190,10 @@ class opcua_namespace():
         deferred and an error is logged.
     """
     if not isinstance(xmlelement, dom.Element):
-      log(self,  "Error: Can not create node from invalid XMLElement", LOG_LEVEL_ERROR)
+      logger.error( "Error: Can not create node from invalid XMLElement")
       return
 
-    # An ID is manditory for everything but aliases!
+    # An ID is mandatory for everything but aliases!
     id = None
     for idname in ['NodeId', 'NodeID', 'nodeid']:
       if xmlelement.hasAttribute(idname):
@@ -199,17 +202,17 @@ class opcua_namespace():
       self.buildAliasList(xmlelement)
       return
     elif id == None:
-      log(self,  "Error: XMLElement has no id, node will not be created!", LOG_LEVEL_INFO)
+      logger.info( "Error: XMLElement has no id, node will not be created!")
       return
     else:
       id = opcua_node_id_t(id)
 
     if str(id) in self.nodeids:
       # Normal behavior: Do not allow duplicates, first one wins
-      #log(self,  "XMLElement with duplicate ID " + str(id) + " found, node will not be created!", LOG_LEVEL_ERROR)
+      #logger.error( "XMLElement with duplicate ID " + str(id) + " found, node will not be created!")
       #return
       # Open62541 behavior for header generation: Replace the duplicate with the new node
-      log(self,  "XMLElement with duplicate ID " + str(id) + " found, node will be replaced!", LOG_LEVEL_INFO)
+      logger.info( "XMLElement with duplicate ID " + str(id) + " found, node will be replaced!")
       nd = self.getNodeByIDString(str(id))
       self.nodes.remove(nd)
       self.nodeids.pop(str(nd.id()))
@@ -232,7 +235,7 @@ class opcua_namespace():
     elif (ndtype == 'referencetype'):
       node = opcua_node_referenceType_t(id, self)
     else:
-      log(self,  "No node constructor for type " + ndtype, LOG_LEVEL_ERROR)
+      logger.error( "No node constructor for type " + ndtype)
 
     if node != None:
       node.parseXML(xmlelement)
@@ -245,7 +248,7 @@ class opcua_namespace():
     if nd == None:
       return False
 
-    log(self, "Removing nodeId " + str(nodeId), LOG_LEVEL_DEBUG)
+    logger.debug("Removing nodeId " + str(nodeId))
     self.nodes.remove(nd)
     if nd.getInverseReferences() != None:
       for ref in nd.getInverseReferences():
@@ -286,10 +289,10 @@ class opcua_namespace():
     typedict = {}
     UANodeSet = dom.parse(xmldoc).getElementsByTagName("UANodeSet")
     if len(UANodeSet) == 0:
-      log(self,  "Error: No NodeSets found", LOG_LEVEL_ERROR)
+      logger.error( "Error: No NodeSets found")
       return
     if len(UANodeSet) != 1:
-      log(self,  "Error: Found more than 1 Nodeset in XML File", LOG_LEVEL_ERROR)
+      logger.error( "Error: Found more than 1 Nodeset in XML File")
 
     UANodeSet = UANodeSet[0]
     for nd in UANodeSet.childNodes:
@@ -300,7 +303,7 @@ class opcua_namespace():
       if ndType[:2] == "ua":
         ndType = ndType[2:]
       elif not ndType in self.knownNodeTypes:
-        log(self, "XML Element or NodeType " + ndType + " is unknown and will be ignored", LOG_LEVEL_WARN)
+        logger.warn("XML Element or NodeType " + ndType + " is unknown and will be ignored")
         continue
 
       if not ndType in typedict:
@@ -309,7 +312,7 @@ class opcua_namespace():
         typedict[ndType] = typedict[ndType] + 1
 
       self.createNode(ndType, nd)
-    log(self, "Currently " + str(len(self.nodes)) + " nodes in address space. Type distribution for this run was: " + str(typedict))
+    logger.debug("Currently " + str(len(self.nodes)) + " nodes in address space. Type distribution for this run was: " + str(typedict))
 
   def linkOpenPointers(self):
     """ Substitutes symbolic NodeIds in references for actual node instances.
@@ -330,7 +333,7 @@ class opcua_namespace():
     """
     linked = []
 
-    log(self,  str(self.unlinkedItemCount()) + " pointers need to get linked.")
+    logger.debug( str(self.unlinkedItemCount()) + " pointers need to get linked.")
     for l in self.__linkLater__:
       targetLinked = False
       if not l.target() == None and not isinstance(l.target(), opcua_node_t):
@@ -346,30 +349,28 @@ class opcua_namespace():
              l.target()[:3] == "ns=" :
             tgt = self.getNodeByIDString(str(l.target()))
             if tgt == None:
-              log(self, "Failed to link pointer to target (node not found) " + l.target(), LOG_LEVEL_ERROR)
+              logger.error("Failed to link pointer to target (node not found) " + l.target())
             else:
               l.target(tgt)
               targetLinked = True
           else:
-            log(self, "Failed to link pointer to target (target not Alias or Node) " + l.target(), LOG_LEVEL_ERROR)
+            logger.error("Failed to link pointer to target (target not Alias or Node) " + l.target())
         else:
-          log(self, "Failed to link pointer to target (don't know dummy type + " + str(type(l.target())) + " +) " + str(l.target()), LOG_LEVEL_ERROR)
+          logger.error("Failed to link pointer to target (don't know dummy type + " + str(type(l.target())) + " +) " + str(l.target()))
       else:
-        log(self, "Pointer has null target: " + str(l), LOG_LEVEL_ERROR)
+        logger.error("Pointer has null target: " + str(l))
 
 
       referenceLinked = False
       if not l.referenceType() == None:
         if l.referenceType() in self.aliases:
           l.referenceType(self.aliases[l.referenceType()])
-        if l.referenceType()[:2] == "i=" or l.referenceType()[:2] == "g=" or \
-           l.referenceType()[:2] == "b=" or l.referenceType()[:2] == "s=":
-          tgt = self.getNodeByIDString(str(l.referenceType()))
-          if tgt == None:
-            log(self, "Failed to link reference type to target (node not found) " + l.referenceType(), LOG_LEVEL_ERROR)
-          else:
-            l.referenceType(tgt)
-            referenceLinked = True
+        tgt = self.getNodeByIDString(str(l.referenceType()))
+        if tgt == None:
+          logger.error("Failed to link reference type to target (node not found) " + l.referenceType())
+        else:
+          l.referenceType(tgt)
+          referenceLinked = True
       else:
         referenceLinked = True
 
@@ -377,7 +378,7 @@ class opcua_namespace():
         linked.append(l)
 
     # References marked as "not forward" must be inverted (removed from source node, assigned to target node and relinked)
-    log(self, "Inverting reference direction for all references with isForward==False attribute (is this correct!?)", LOG_LEVEL_WARN)
+    logger.warn("Inverting reference direction for all references with isForward==False attribute (is this correct!?)")
     for n in self.nodes:
       for r in n.getReferences():
         if r.isForward() == False:
@@ -388,7 +389,7 @@ class opcua_namespace():
             tgt.addReference(nref)
 
     # Create inverse references for all nodes
-    log(self, "Updating all referencedBy fields in nodes for inverse lookups.")
+    logger.debug("Updating all referencedBy fields in nodes for inverse lookups.")
     for n in self.nodes:
       n.updateInverseReferences()
 
@@ -396,19 +397,19 @@ class opcua_namespace():
       self.__linkLater__.remove(l)
 
     if len(self.__linkLater__) != 0:
-      log(self, str(len(self.__linkLater__)) + " could not be linked.", LOG_LEVEL_WARN)
+      logger.warn(str(len(self.__linkLater__)) + " could not be linked.")
 
   def sanitize(self):
     remove = []
-    log(self, "Sanitizing nodes and references...")
+    logger.debug("Sanitizing nodes and references...")
     for n in self.nodes:
       if n.sanitize() == False:
         remove.append(n)
     if not len(remove) == 0:
-      log(self, str(len(remove)) + " nodes will be removed because they failed sanitation.", LOG_LEVEL_WARN)
+      logger.warn(str(len(remove)) + " nodes will be removed because they failed sanitation.")
     # FIXME: Some variable ns=0 nodes fail because they don't have DataType fields...
     #        How should this be handles!?
-    log(self, "Not actually removing nodes... it's unclear if this is valid or not", LOG_LEVEL_WARN)
+    logger.warn("Not actually removing nodes... it's unclear if this is valid or not")
 
   def getRoot(self):
     """ Returns the first node instance with the browseName "Root".
@@ -425,7 +426,7 @@ class opcua_namespace():
       if isinstance(n, opcua_node_dataType_t):
         n.buildEncoding()
         stat[n.isEncodable()] = stat[n.isEncodable()] + 1
-    log(self, "Type definitions built/passed: " +  str(stat), LOG_LEVEL_DEBUG)
+    logger.debug("Type definitions built/passed: " +  str(stat))
 
   def allocateVariables(self):
     for n in self.nodes:
@@ -448,10 +449,10 @@ class opcua_namespace():
       file.write(n.printDot())
     file.write("}\n")
     file.close()
-  
+
   def getSubTypesOf(self, tdNodes = None, currentNode = None, hasSubtypeRefNode = None):
     # If this is a toplevel call, collect the following information as defaults
-    if tdNodes == None: 
+    if tdNodes == None:
       tdNodes = []
     if currentNode == None:
       currentNode = self.getNodeByBrowseName("HasTypeDefinition")
@@ -462,16 +463,16 @@ class opcua_namespace():
       hasSubtypeRefNode = self.getNodeByBrowseName("HasSubtype")
       if hasSubtypeRefNode == None:
         return tdNodes
-    
+
     # collect all subtypes of this node
     for ref in currentNode.getReferences():
       if ref.isForward() and ref.referenceType().id() == hasSubtypeRefNode.id():
         tdNodes.append(ref.target())
         self.getTypeDefinitionNodes(tdNodes=tdNodes, currentNode = ref.target(), hasSubtypeRefNode=hasSubtypeRefNode)
-    
+
     return tdNodes
-      
-  
+
+
   def printDotGraphWalk(self, depth=1, filename="out.dot", rootNode=None, followInverse = False, excludeNodeIds=[]):
     """ Outputs a graphiz/dot description the nodes centered around rootNode.
 
@@ -545,14 +546,14 @@ class opcua_namespace():
         minweight = w
         minweightnd = row[0]
     return (rind, minweightnd, minweight)
-  
+
   def reorderNodesMinDependencies(self):
     # create a matrix represtantion of all node
     #
     nmatrix = []
     for n in range(0,len(self.nodes)):
       nmatrix.append([None] + [0]*len(self.nodes))
-    
+
     typeRefs = []
     tn = self.getNodeByBrowseName("HasTypeDefinition")
     if tn != None:
@@ -563,13 +564,13 @@ class opcua_namespace():
     if tn  != None:
       subTypeRefs.append(tn)
       subTypeRefs = subTypeRefs + self.getSubTypesOf(currentNode=tn)
-    
-    log(self, "Building connectivity matrix for node order optimization.")
+
+    logger.debug("Building connectivity matrix for node order optimization.")
     # Set column 0 to contain the node
     for node in self.nodes:
       nind = self.nodes.index(node)
       nmatrix[nind][0] = node
-      
+
     # Determine the dependencies of all nodes
     for node in self.nodes:
       nind = self.nodes.index(node)
@@ -586,8 +587,8 @@ class opcua_namespace():
           # Else the target depends on us
           elif ref.isForward():
             nmatrix[tind][nind+1] += 1
-    
-    log(self, "Using Djikstra topological sorting to determine printing order.")
+
+    logger.debug("Using Djikstra topological sorting to determine printing order.")
     reorder = []
     while len(reorder) < len(self.nodes):
       (nind, node, w) = self.__reorder_getMinWeightNode__(nmatrix)
@@ -604,23 +605,23 @@ class opcua_namespace():
             nmatrix[tind][nind+1] -= 1
       nmatrix[nind][0] = None
     self.nodes = reorder
-    log(self, "Nodes reordered.")
+    logger.debug("Nodes reordered.")
     return
-  
+
   def printOpen62541Header(self, printedExternally=[], supressGenerationOfAttribute=[], outfilename=""):
     unPrintedNodes = []
     unPrintedRefs  = []
     code = []
     header = []
-    
+
     # Reorder our nodes to produce a bare minimum of bootstrapping dependencies
-    log(self, "Reordering nodes for minimal dependencies during printing.")
+    logger.debug("Reordering nodes for minimal dependencies during printing.")
     self.reorderNodesMinDependencies()
-    
+
     # Some macros (UA_EXPANDEDNODEID_MACRO()...) are easily created, but
     # bulky. This class will help to offload some code.
     codegen = open62541_MacroHelper(supressGenerationOfAttribute=supressGenerationOfAttribute)
-    
+
     # Populate the unPrinted-Lists with everything we have.
     # Every Time a nodes printfunction is called, it will pop itself and
     #   all printed references from these lists.
@@ -628,13 +629,13 @@ class opcua_namespace():
       if not n in printedExternally:
         unPrintedNodes.append(n)
       else:
-        log(self, "Node " + str(n.id()) + " is being ignored.", LOG_LEVEL_DEBUG)
+        logger.debug("Node " + str(n.id()) + " is being ignored.")
     for n in unPrintedNodes:
       for r in n.getReferences():
         if (r.target() != None) and (r.target().id() != None) and (r.parent() != None):
           unPrintedRefs.append(r)
 
-    log(self, str(len(unPrintedNodes)) + " Nodes, " + str(len(unPrintedRefs)) +  "References need to get printed.", LOG_LEVEL_DEBUG)
+    logger.debug(str(len(unPrintedNodes)) + " Nodes, " + str(len(unPrintedRefs)) +  "References need to get printed.")
     header.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
     code.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
 
@@ -652,10 +653,10 @@ class opcua_namespace():
     header.append('#include "open62541.h"')
     header.append('#define NULL ((void *)0)')
     header.append('#endif')
-      
+
     code.append('#include "'+outfilename+'.h"')
     code.append("UA_INLINE void "+outfilename+"(UA_Server *server) {")
-    
+
     # Before printing nodes, we need to request additional namespace arrays from the server
     for nsid in self.namespaceIdentifiers:
       if nsid == 0 or nsid==1:
@@ -664,11 +665,11 @@ class opcua_namespace():
         name =  self.namespaceIdentifiers[nsid]
         name = name.replace("\"","\\\"")
         code.append("UA_Server_addNamespace(server, \"" + name.encode('UTF-8') + "\");")
-    
+
     # Find all references necessary to create the namespace and
     # "Bootstrap" them so all other nodes can safely use these referencetypes whenever
     # they can locate both source and target of the reference.
-    log(self, "Collecting all references used in the namespace.", LOG_LEVEL_DEBUG)
+    logger.debug("Collecting all references used in the namespace.")
     refsUsed = []
     for n in self.nodes:
       # Since we are already looping over all nodes, use this chance to print NodeId defines
@@ -676,39 +677,39 @@ class opcua_namespace():
         nc = n.nodeClass()
         if nc != NODE_CLASS_OBJECT and nc != NODE_CLASS_VARIABLE and nc != NODE_CLASS_VIEW:
           header = header + codegen.getNodeIdDefineString(n)
-          
+
       # Now for the actual references...
       for r in n.getReferences():
         # Only print valid refernces in namespace 0 (users will not want their refs bootstrapped)
         if not r.referenceType() in refsUsed and r.referenceType() != None and r.referenceType().id().ns == 0:
           refsUsed.append(r.referenceType())
-    log(self, str(len(refsUsed)) + " reference types are used in the namespace, which will now get bootstrapped.", LOG_LEVEL_DEBUG)
+    logger.debug(str(len(refsUsed)) + " reference types are used in the namespace, which will now get bootstrapped.")
     for r in refsUsed:
       code = code + r.printOpen62541CCode(unPrintedNodes, unPrintedRefs);
-    
+
     header.append("extern void "+outfilename+"(UA_Server *server);\n")
     header.append("#endif /* "+outfilename.upper()+"_H_ */")
-    
+
     # Note to self: do NOT - NOT! - try to iterate over unPrintedNodes!
     #               Nodes remove themselves from this list when printed.
-    log(self, "Printing all other nodes.", LOG_LEVEL_DEBUG)
+    logger.debug("Printing all other nodes.")
     for n in self.nodes:
       code = code + n.printOpen62541CCode(unPrintedNodes, unPrintedRefs, supressGenerationOfAttribute=supressGenerationOfAttribute)
 
     if len(unPrintedNodes) != 0:
-      log(self, "" + str(len(unPrintedNodes)) + " nodes could not be translated to code.", LOG_LEVEL_WARN)
+      logger.warn("" + str(len(unPrintedNodes)) + " nodes could not be translated to code.")
     else:
-      log(self, "Printing suceeded for all nodes", LOG_LEVEL_DEBUG)
+      logger.debug("Printing suceeded for all nodes")
 
     if len(unPrintedRefs) != 0:
-      log(self, "Attempting to print " + str(len(unPrintedRefs)) + " unprinted references.", LOG_LEVEL_DEBUG)
+      logger.debug("Attempting to print " + str(len(unPrintedRefs)) + " unprinted references.")
       tmprefs = []
       for r in unPrintedRefs:
         if  not (r.target() not in unPrintedNodes) and not (r.parent() in unPrintedNodes):
           if not isinstance(r.parent(), opcua_node_t):
-            log(self, "Reference has no parent!", LOG_LEVEL_DEBUG)
+            logger.debug("Reference has no parent!")
           elif not isinstance(r.parent().id(), opcua_node_id_t):
-            log(self, "Parents nodeid is not a nodeID!", LOG_LEVEL_DEBUG)
+            logger.debug("Parents nodeid is not a nodeID!")
           else:
             if (len(tmprefs) == 0):
               code.append("//  Creating leftover references:")
@@ -719,9 +720,9 @@ class opcua_namespace():
       for r in tmprefs:
         unPrintedRefs.remove(r)
       if len(unPrintedRefs) != 0:
-        log(self, "" + str(len(unPrintedRefs)) + " references could not be translated to code.", LOG_LEVEL_WARN)
+        logger.warn("" + str(len(unPrintedRefs)) + " references could not be translated to code.")
     else:
-      log(self, "Printing succeeded for all references", LOG_LEVEL_DEBUG)
+      logger.debug("Printing succeeded for all references")
 
     code.append("}")
     return (header,code)
@@ -734,20 +735,20 @@ class testing:
   def __init__(self):
     self.namespace = opcua_namespace("testing")
 
-    log(self, "Phase 1: Reading XML file nodessets")
+    logger.debug("Phase 1: Reading XML file nodessets")
     self.namespace.parseXML("Opc.Ua.NodeSet2.xml")
     #self.namespace.parseXML("Opc.Ua.NodeSet2.Part4.xml")
     #self.namespace.parseXML("Opc.Ua.NodeSet2.Part5.xml")
     #self.namespace.parseXML("Opc.Ua.SimulationNodeSet2.xml")
 
-    log(self, "Phase 2: Linking address space references and datatypes")
+    logger.debug("Phase 2: Linking address space references and datatypes")
     self.namespace.linkOpenPointers()
     self.namespace.sanitize()
 
-    log(self, "Phase 3: Comprehending DataType encoding rules")
+    logger.debug("Phase 3: Comprehending DataType encoding rules")
     self.namespace.buildEncodingRules()
 
-    log(self, "Phase 4: Allocating variable value data")
+    logger.debug("Phase 4: Allocating variable value data")
     self.namespace.allocateVariables()
 
     bin = self.namespace.buildBinary()
@@ -775,7 +776,7 @@ class testing:
         ns.append(n)
       print("...done, " + str(len(ns)) + " nodes discovered")
 
-    log(self, "Phase 5: Printing pretty graph")
+    logger.debug("Phase 5: Printing pretty graph")
     self.namespace.printDotGraphWalk(depth=1, rootNode=self.namespace.getNodeByIDString("i=84"), followInverse=False, excludeNodeIds=["i=29", "i=22", "i=25"])
     #self.namespace.printDot()
 
@@ -783,17 +784,17 @@ class testing_open62541_header:
   def __init__(self):
     self.namespace = opcua_namespace("testing")
 
-    log(self, "Phase 1: Reading XML file nodessets")
+    logger.debug("Phase 1: Reading XML file nodessets")
     self.namespace.parseXML("Opc.Ua.NodeSet2.xml")
     #self.namespace.parseXML("Opc.Ua.NodeSet2.Part4.xml")
     #self.namespace.parseXML("Opc.Ua.NodeSet2.Part5.xml")
     #self.namespace.parseXML("Opc.Ua.SimulationNodeSet2.xml")
 
-    log(self, "Phase 2: Linking address space references and datatypes")
+    logger.debug("Phase 2: Linking address space references and datatypes")
     self.namespace.linkOpenPointers()
     self.namespace.sanitize()
 
-    log(self, "Phase 3: Calling C Printers")
+    logger.debug("Phase 3: Calling C Printers")
     code = self.namespace.printOpen62541Header()
 
     codeout = open("./open62541_namespace.c", "w+")

+ 113 - 111
tools/pyUANamespace/ua_node_types.py

@@ -17,11 +17,13 @@
 ###
 
 import sys
-from logger import *;
+import logging
 from ua_builtin_types import *;
 from open62541_MacroHelper import open62541_MacroHelper
 from ua_constants import *
 
+logger = logging.getLogger(__name__)
+
 def getNextElementNode(xmlvalue):
   if xmlvalue == None:
     return None
@@ -215,10 +217,10 @@ class opcua_node_id_t():
 
   def __str__(self):
     return self.__mystrname__
-  
-  def __eq__(self, nodeId2):    
+
+  def __eq__(self, nodeId2):
     return (self.toString() == nodeId2.toString())
-  
+
   def __repr__(self):
     return self.__mystrname__
 
@@ -322,11 +324,11 @@ class opcua_node_t:
     if not node in self.__node_referencedBy__:
       if not self.hasReferenceTarget(node):
         self.__node_referencedBy__.append(opcua_referencePointer_t(node, hidden=True, parentNode=self))
-#        log(self, self.__node_browseName__ + " added reverse reference to " + str(node.__node_browseName__), LOG_LEVEL_DEBUG)
+#        logger.debug(self.__node_browseName__ + " added reverse reference to " + str(node.__node_browseName__))
 #      else:
-#        log(self, self.__node_browseName__ + " refusing reverse reference to " + str(node.__node_browseName__)  + " (referenced normally)", LOG_LEVEL_DEBUG)
+#        logger.debug(self.__node_browseName__ + " refusing reverse reference to " + str(node.__node_browseName__)  + " (referenced normally)")
 #    else:
-#      log(self, self.__node_browseName__ + " refusing reverse reference to " + str(node.__node_browseName__) + " (already reversed referenced)", LOG_LEVEL_DEBUG)
+#      logger.debug(self.__node_browseName__ + " refusing reverse reference to " + str(node.__node_browseName__) + " (already reversed referenced)")
 
   def getReferences(self):
     return self.__node_references__
@@ -389,10 +391,10 @@ class opcua_node_t:
     for r in self.getReferences():
       if isinstance(r.target(), opcua_node_t):
         if not r.target().hasInverseReferenceTarget(self):
-          #log(self, self.__node_browseName__ + " req. rev. referencing in" + str(r.target().__node_browseName__), LOG_LEVEL_DEBUG)
+          #logger.debug(self.__node_browseName__ + " req. rev. referencing in" + str(r.target().__node_browseName__))
           r.target().addInverseReferenceTarget(self)
       #else:
-        #log(self, "Cannot register inverse link to " + str(r.target()) + " (not a node)")
+        #logger.debug("Cannot register inverse link to " + str(r.target()) + " (not a node)")
 
   def id(self):
     return self.__node_id__
@@ -464,7 +466,7 @@ class opcua_node_t:
         with an actual instance of an opcua_node_t.
     """
     if not xmlelement.tagName == "References":
-      log(self, "XMLElement passed is not a reference list", LOG_LEVEL_ERROR)
+      logger.error("XMLElement passed is not a reference list")
       return
     for ref in xmlelement.childNodes:
       if ref.nodeType == ref.ELEMENT_NODE:
@@ -478,7 +480,7 @@ class opcua_node_t:
             if "false" in av.lower():
               dummy.isForward(False)
           else:
-            log(self, "Don't know how to process attribute " + at + "(" + av + ") for references.", LOG_LEVEL_ERROR)
+            logger.error("Don't know how to process attribute " + at + "(" + av + ") for references.")
 
   def printDot(self):
     cleanname = "node_" + str(self.id()).replace(";","").replace("=","")
@@ -491,31 +493,31 @@ class opcua_node_t:
           dot = dot + cleanname + " -> " + tgtname + " [label=\"" + str(r.referenceType().browseName()) + "\"]\n"
         else:
           if len(r.referenceType().inverseName()) == 0:
-            log(self, "Inverse name of reference is null " + str(r.referenceType().id()), LOG_LEVEL_WARN)
+            logger.warn("Inverse name of reference is null " + str(r.referenceType().id()))
           dot = dot + cleanname + " -> " + tgtname + " [label=\"" + str(r.referenceType().inverseName()) + "\"]\n"
     return dot
 
   def sanitize(self):
     """ Check the health of this node.
 
-        Return True if all manditory attributes are valid and all references have been
+        Return True if all mandatory attributes are valid and all references have been
         correclty linked to nodes. Returns False on failure, which should indicate
         that this node needs to be removed from the namespace.
     """
     # Do we have an id?
     if not isinstance(self.id(), opcua_node_id_t):
-      log(self, "HELP! I'm an id'less node!", LOG_LEVEL_ERROR)
+      logger.error("HELP! I'm an id'less node!")
       return False
 
     # Remove unlinked references
     tmp = []
     for r in self.getReferences():
       if not isinstance(r, opcua_referencePointer_t):
-        log(self, "Reference is not a reference!?.", LOG_LEVEL_ERROR)
+        logger.error("Reference is not a reference!?.")
       elif not isinstance(r.referenceType(), opcua_node_t):
-        log(self, "Reference has no valid reference type and will be removed.", LOG_LEVEL_ERROR)
+        logger.error("Reference has no valid reference type and will be removed.")
       elif not isinstance(r.target(), opcua_node_t):
-        log(self, "Reference to " + str(r.target()) + " is not a node. It has been removed.", LOG_LEVEL_WARN)
+        logger.warn("Reference to " + str(r.target()) + " is not a node. It has been removed.")
       else:
         tmp.append(r)
     self.__node_references__ = tmp
@@ -524,12 +526,12 @@ class opcua_node_t:
     tmp = []
     for r in self.getInverseReferences():
       if not isinstance(r.target(), opcua_node_t):
-        log(self, "Invers reference to " + str(r.target()) + " does not reference a real node. It has been removed.", LOG_LEVEL_WARN)
+        logger.warn("Invers reference to " + str(r.target()) + " does not reference a real node. It has been removed.")
       else:
         if r.target().hasReferenceTarget(self):
           tmp.append(r)
         else:
-          log(self, "Node " + str(self.id()) + " was falsely under the impression that it is referenced by " + str(r.target().id()), LOG_LEVEL_WARN)
+          logger.warn("Node " + str(self.id()) + " was falsely under the impression that it is referenced by " + str(r.target().id()))
     self.__node_referencedBy__ = tmp
 
     # Remove references from inverse list if we can reach this not "the regular way"
@@ -539,7 +541,7 @@ class opcua_node_t:
       if not self.hasReferenceTarget(r.target()):
         tmp.append(r)
       else:
-        log(self, "Removing unnecessary inverse reference to " + str(r.target.id()))
+        logger.debug("Removing unnecessary inverse reference to " + str(r.target.id()))
     self.__node_referencedBy__ = tmp
 
     return self.sanitizeSubType()
@@ -629,7 +631,7 @@ class opcua_node_t:
 
   def printXML(self):
     pass
-  
+
   def printOpen62541CCode_SubtypeEarly(self, bootstrapping = True):
     """ printOpen62541CCode_SubtypeEarly
 
@@ -637,11 +639,11 @@ class opcua_node_t:
         the actual UA_Server_addNode or UA_NodeStore_insert calls.
     """
     return []
-  
+
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     """ printOpen62541CCode_Subtype
 
-        Appends node type specific information to the nodes  UA_Server_addNode 
+        Appends node type specific information to the nodes  UA_Server_addNode
         or UA_NodeStore_insert calls.
     """
     return []
@@ -662,10 +664,10 @@ class opcua_node_t:
 
     # Just to be sure...
     if not (self in unPrintedNodes):
-      log(self, str(self) + " attempted to reprint already printed node " + str(self)+ ".", LOG_LEVEL_WARN)
+      logger.warn(str(self) + " attempted to reprint already printed node " + str(self)+ ".")
       return []
 
-    # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace   
+    # If we are being passed a parent node by the namespace, use that for registering ourselves in the namespace
     # Note: getFirstParentNode will return [parentNode, referenceToChild]
     (parentNode, parentRef) = self.getFirstParentNode()
     if not (parentNode in unPrintedNodes) and (parentNode != None) and (parentRef.referenceType() != None):
@@ -691,13 +693,13 @@ class opcua_node_t:
       code.append("UA_RCU_LOCK();")
       code.append("UA_NodeStore_insert(server->nodestore, (UA_Node*) " + self.getCodePrintableID() + ");")
       code.append("UA_RCU_UNLOCK();")
-      
+
     # Try to print all references to nodes that already exist
     # Note: we know the reference types exist, because the namespace class made sure they were
     #       the first ones being printed
     tmprefs = []
     for r in self.getReferences():
-      #log(self, "Checking if reference from " + str(r.parent()) + "can be created...", LOG_LEVEL_DEBUG)
+      #logger.debug("Checking if reference from " + str(r.parent()) + "can be created...")
       if not (r.target() in unPrintedNodes):
         if r in unPrintedReferences:
           if (len(tmprefs) == 0):
@@ -712,12 +714,12 @@ class opcua_node_t:
     # not exist...
     tmprefs = []
     for r in unPrintedReferences:
-      #log(self, "Checking if another reference " + str(r.target()) + "can be created...", LOG_LEVEL_DEBUG)
+      #logger.debug("Checking if another reference " + str(r.target()) + "can be created...")
       if (r.target() == self) and not (r.parent() in unPrintedNodes):
         if not isinstance(r.parent(), opcua_node_t):
-          log(self, "Reference has no parent!", LOG_LEVEL_DEBUG)
+          logger.debug("Reference has no parent!")
         elif not isinstance(r.parent().id(), opcua_node_id_t):
-          log(self, "Parents nodeid is not a nodeID!", LOG_LEVEL_DEBUG)
+          logger.debug("Parents nodeid is not a nodeID!")
         else:
           if (len(tmprefs) == 0):
             code.append("//  Creating this node has resolved the following open references:")
@@ -731,7 +733,7 @@ class opcua_node_t:
     if self in unPrintedNodes:
       # This is necessery to make printing work at all!
       unPrintedNodes.remove(self)
-    
+
     code.append("} while(0);")
     return code
 
@@ -770,7 +772,7 @@ class opcua_node_referenceType_t(opcua_node_t):
 
   def sanitizeSubType(self):
     if not isinstance(self.referenceType(), opcua_referencePointer_t):
-      log(self, "ReferenceType " + str(self.referenceType()) + " of " + str(self.id()) + " is not a pointer (ReferenceType is manditory for references).", LOG_LEVEL_ERROR)
+      logger.error("ReferenceType " + str(self.referenceType()) + " of " + str(self.id()) + " is not a pointer (ReferenceType is mandatory for references).")
       self.__reference_referenceType__ = None
       return False
     return True
@@ -793,19 +795,19 @@ class opcua_node_referenceType_t(opcua_node_t):
           self.isAbstract(True)
         xmlelement.removeAttribute(at)
       else:
-        log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_ERROR)
+        logger.warn("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
         if x.tagName == "InverseName":
           self.inverseName(str(unicode(x.firstChild.data)))
         else:
-          log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
+          logger.warn( "Unprocessable XML Element: " + x.tagName)
 
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
-    
+
     # Detect if this is bootstrapping or if we are attempting to use userspace...
     if bootstrapping == False:
       typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
@@ -820,19 +822,19 @@ class opcua_node_referenceType_t(opcua_node_t):
             myTypeRef = ref
             break
       if myTypeRef==None:
-        log(self, str(self) + " failed to locate a type definition, assuming BaseDataType.", LOG_LEVEL_WARN)
+        logger.warn(str(self) + " failed to locate a type definition, assuming BaseDataType.")
         code.append("       // No valid typeDefinition found; assuming BaseDataType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
       else:
         code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
         while myTypeRef in unPrintedReferences:
           unPrintedReferences.remove(myTypeRef)
-          
+
       code.append("       UA_LOCALIZEDTEXT(\"\",\"" + str(self.inverseName()) + "\"),");
       code.append("       // FIXME: Missing, isAbstract")
       code.append("       // FIXME: Missing, symmetric")
       return code
-    
+
     if self.isAbstract():
       code.append(self.getCodePrintableID() + "->isAbstract = true;")
     if self.symmetric():
@@ -863,16 +865,16 @@ class opcua_node_object_t(opcua_node_t):
         # Silently ignore this one
         xmlelement.removeAttribute(at)
       else:
-        log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_ERROR)
+        logger.error("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
-        log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
+        logger.info( "Unprocessable XML Element: " + x.tagName)
 
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
-      
+
     # Detect if this is bootstrapping or if we are attempting to use userspace...
     if bootstrapping == False:
       typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
@@ -887,17 +889,17 @@ class opcua_node_object_t(opcua_node_t):
             myTypeRef = ref
             break
       if myTypeRef==None:
-        log(self, str(self) + " failed to locate a type definition, assuming BaseObjectType.", LOG_LEVEL_WARN)
+        logger.warn(str(self) + " failed to locate a type definition, assuming BaseObjectType.")
         code.append("       // No valid typeDefinition found; assuming BaseObjectType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
       else:
         code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
         while myTypeRef in unPrintedReferences:
           unPrintedReferences.remove(myTypeRef)
-      
+
       #FIXME: No event notifier in UA_Server_addNode call!
       return code
-    
+
     # We are being bootstrapped! Add the raw attributes to the node.
     code.append(self.getCodePrintableID() + "->eventNotifier = (UA_Byte) " + str(self.eventNotifier()) + ";")
     return code
@@ -971,32 +973,32 @@ class opcua_node_variable_t(opcua_node_t):
 
   def sanitizeSubType(self):
     if not isinstance(self.dataType(), opcua_referencePointer_t):
-      log(self, "DataType " + str(self.dataType()) + " of " + str(self.id()) + " is not a pointer (DataType is manditory for variables).", LOG_LEVEL_ERROR)
+      logger.error("DataType " + str(self.dataType()) + " of " + str(self.id()) + " is not a pointer (DataType is mandatory for variables).")
       self.__dataType__ = None
       return False
 
     if not isinstance(self.dataType().target(), opcua_node_t):
-      log(self, "DataType " + str(self.dataType().target()) + " of " + str(self.id()) + " does not point to a node (DataType is manditory for variables).", LOG_LEVEL_ERROR)
+      logger.error("DataType " + str(self.dataType().target()) + " of " + str(self.id()) + " does not point to a node (DataType is mandatory for variables).")
       self.__dataType__ = None
       return False
     return True
 
   def allocateValue(self):
     if not isinstance(self.dataType(), opcua_referencePointer_t):
-      log(self, "Variable " + self.browseName() + "/" + str(self.id()) + " does not reference a valid dataType.", LOG_LEVEL_ERROR)
+      logger.error("Variable " + self.browseName() + "/" + str(self.id()) + " does not reference a valid dataType.")
       return False
 
     if not isinstance(self.dataType().target(), opcua_node_dataType_t):
-      log(self, "Variable " + self.browseName() + "/" + str(self.id()) + " does not have a valid dataType reference.", LOG_LEVEL_ERROR)
+      logger.error("Variable " + self.browseName() + "/" + str(self.id()) + " does not have a valid dataType reference.")
       return False
 
     if not self.dataType().target().isEncodable():
-      log(self, "DataType for Variable " + self.browseName() + "/" + str(self.id()) + " is not encodable.", LOG_LEVEL_ERROR)
+      logger.error("DataType for Variable " + self.browseName() + "/" + str(self.id()) + " is not encodable.")
       return False
 
     # FIXME: Don't build at all or allocate "defaults"? I'm for not building at all.
     if self.__xmlValueDef__ == None:
-      #log(self, "Variable " + self.browseName() + "/" + str(self.id()) + " is not initialized. No memory will be allocated.", LOG_LEVEL_WARN)
+      #logger.warn("Variable " + self.browseName() + "/" + str(self.id()) + " is not initialized. No memory will be allocated.")
       return False
 
     self.value(opcua_value_t(self))
@@ -1034,7 +1036,7 @@ class opcua_node_variable_t(opcua_node_t):
         # Silently ignore this one
         xmlelement.removeAttribute(at)
       else:
-        log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_ERROR)
+        logger.error("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
@@ -1043,7 +1045,7 @@ class opcua_node_variable_t(opcua_node_t):
           # which can only be done if the namespace is linked.
           # Store the Value for later parsing
           self.__xmlValueDef__ = x
-          #log(self,  "Value description stored for later elaboration.", LOG_LEVEL_DEBUG)
+          #logger.debug( "Value description stored for later elaboration.")
         elif x.tagName == "DataType":
           self.dataType(opcua_referencePointer_t(str(av), parentNode=self))
           # dataType needs to be linked to a node once the namespace is read
@@ -1062,7 +1064,7 @@ class opcua_node_variable_t(opcua_node_t):
           if "true" in x.firstChild.data.lower():
             self.historizing(True)
         else:
-          log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
+          logger.info( "Unprocessable XML Element: " + x.tagName)
 
   def printOpen62541CCode_SubtypeEarly(self, bootstrapping = True):
     code = []
@@ -1078,11 +1080,11 @@ class opcua_node_variable_t(opcua_node_t):
       code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_alloca(sizeof(UA_Variant));")
       code.append("UA_Variant_init(" + self.getCodePrintableID() + "_variant);")
     return code
-  
+
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
-    
+
     # Detect if this is bootstrapping or if we are attempting to use userspace...
     if bootstrapping == False:
       code.append("       " + self.getCodePrintableID() + "_variant, ")
@@ -1091,7 +1093,7 @@ class opcua_node_variable_t(opcua_node_t):
       code.append("       // FIXME: missing userAccessLevel")
       code.append("       // FIXME: missing valueRank")
       return code
-    
+
     if self.historizing():
       code.append(self.getCodePrintableID() + "->historizing = true;")
 
@@ -1145,15 +1147,15 @@ class opcua_node_method_t(opcua_node_t):
         # dataType needs to be linked to a node once the namespace is read
         self.getNamespace().linkLater(self.methodDeclaration())
       else:
-        log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_ERROR)
+        logger.error("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
-        log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
+        logger.info( "Unprocessable XML Element: " + x.tagName)
 
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
-    
+
     # Detect if this is bootstrapping or if we are attempting to use userspace...
     if bootstrapping == False:
       code.append("       // Note: in/outputArguments are added by attaching the variable nodes,")
@@ -1165,7 +1167,7 @@ class opcua_node_method_t(opcua_node_t):
       code.append("       // FIXME: Missing executable")
       code.append("       // FIXME: Missing userExecutable")
       return code
-    
+
     # UA_False is default for booleans on _init()
     if self.executable():
       code.append(self.getCodePrintableID() + "->executable = true;")
@@ -1193,16 +1195,16 @@ class opcua_node_objectType_t(opcua_node_t):
           self.isAbstract(False)
         xmlelement.removeAttribute(at)
       else:
-        log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_ERROR)
+        logger.error("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
-        log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
+        logger.info( "Unprocessable XML Element: " + x.tagName)
 
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper();
-    
+
     # Detect if this is bootstrapping or if we are attempting to use userspace...
     if bootstrapping == False:
       typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
@@ -1217,7 +1219,7 @@ class opcua_node_objectType_t(opcua_node_t):
             myTypeRef = ref
             break
       if myTypeRef==None:
-        log(self, str(self) + " failed to locate a type definition, assuming BaseObjectType.", LOG_LEVEL_WARN)
+        logger.warn(str(self) + " failed to locate a type definition, assuming BaseObjectType.")
         code.append("       // No valid typeDefinition found; assuming BaseObjectType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),")
       else:
@@ -1225,12 +1227,12 @@ class opcua_node_objectType_t(opcua_node_t):
         while myTypeRef in unPrintedReferences:
           code.append("       // removed " + str(myTypeRef))
           unPrintedReferences.remove(myTypeRef)
-      
+
       if (self.isAbstract()):
         code.append("       true,")
       else:
         code.append("       false,")
-    
+
     # Fallback mode for bootstrapping
     if (self.isAbstract()):
       code.append(self.getCodePrintableID() + "->isAbstract = true;")
@@ -1255,7 +1257,7 @@ class opcua_node_variableType_t(opcua_node_t):
     self.__xmlDefinition__ = None
 
   def value(self, data=None):
-    log(self, "Setting data not implemented!", LOG_LEVEL_ERROR)
+    logger.error("Setting data not implemented!")
 
   def dataType(self, data=None):
     if data != None:
@@ -1282,15 +1284,15 @@ class opcua_node_variableType_t(opcua_node_t):
     # but if it does have a node set, it must obviously be a valid node
     if not self.dataType() != None:
       if not isinstance(self.dataType(), opcua_referencePointer_t):
-        log(self, "DataType attribute of " + str(self.id()) + " is not a pointer", LOG_LEVEL_ERROR)
+        logger.error("DataType attribute of " + str(self.id()) + " is not a pointer")
         return False
       else:
         if not isinstance(self.dataType().target(), opcua_node_t):
-          log(self, "DataType attribute of " + str(self.id()) + " does not point to a node", LOG_LEVEL_ERROR)
+          logger.error("DataType attribute of " + str(self.id()) + " does not point to a node")
           return False
     else:
       # FIXME: It's unclear wether this is ok or not.
-      log(self, "DataType attribute of variableType " + str(self.id()) + " is not defined.", LOG_LEVEL_WARN)
+      logger.warn("DataType attribute of variableType " + str(self.id()) + " is not defined.")
       return False
 
   def parseXMLSubType(self, xmlelement):
@@ -1304,22 +1306,22 @@ class opcua_node_variableType_t(opcua_node_t):
       elif at == "ValueRank":
         self.valueRank(int(av))
         if self.valueRank() != -1:
-          log(self, "Array's or matrices are only permitted in variables and not supported for variableTypes. This attribute will effectively be ignored.", LOG_LEVEL_WARN)
+          logger.warn("Array's or matrices are only permitted in variables and not supported for variableTypes. This attribute (" + at + "=" + av + ") will effectively be ignored.")
         xmlelement.removeAttribute(at)
       elif at == "DataType":
         self.dataType(opcua_referencePointer_t(str(av), parentNode=self))
         # dataType needs to be linked to a node once the namespace is read
         self.getNamespace().linkLater(self.dataType())
       else:
-        log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_ERROR)
+        logger.error("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
         if x.tagName == "Definition":
           self.__xmlDefinition__ = x
-          log(self,  "Definition stored for future processing", LOG_LEVEL_DEBUG)
+          logger.debug( "Definition stored for future processing")
         else:
-          log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
+          logger.info( "Unprocessable XML Element: " + x.tagName)
 
   def printOpen62541CCode_SubtypeEarly(self, bootstrapping = True):
     code = []
@@ -1335,11 +1337,11 @@ class opcua_node_variableType_t(opcua_node_t):
       code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_alloca(sizeof(UA_Variant));")
       code.append("UA_Variant_init(" + self.getCodePrintableID() + "_variant);")
     return code
-  
+
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
-    
+
     if bootstrapping == False:
       code.append("       " + self.getCodePrintableID() + "_variant, ")
       code.append("       " + str(self.valueRank()) + ",")
@@ -1348,12 +1350,12 @@ class opcua_node_variableType_t(opcua_node_t):
       else:
         code.append("       false,")
       return code
-    
+
     if (self.isAbstract()):
       code.append(self.getCodePrintableID() + "->isAbstract = true;")
     else:
       code.append(self.getCodePrintableID() + "->isAbstract = false;")
-    
+
     # The variant is guaranteed to exist by SubtypeEarly()
     code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
     code.append(self.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
@@ -1482,22 +1484,22 @@ class opcua_node_dataType_t(opcua_node_t):
 
     if self.__encodingBuilt__ == True:
       if self.isEncodable():
-        log(self, prefix + str(self.__baseTypeEncoding__) + " (already analyzed)")
+        logger.debug(prefix + str(self.__baseTypeEncoding__) + " (already analyzed)")
       else:
-        log(self,  prefix + str(self.__baseTypeEncoding__) + "(already analyzed, not encodable!)")
+        logger.debug( prefix + str(self.__baseTypeEncoding__) + "(already analyzed, not encodable!)")
       return self.__baseTypeEncoding__
     self.__encodingBuilt__ = True # signify that we have attempted to built this type
     self.__encodable__ = True
 
     if indent==0:
-      log(self, "Parsing DataType " + self.browseName() + " (" + str(self.id()) + ")")
+      logger.debug("Parsing DataType " + self.browseName() + " (" + str(self.id()) + ")")
 
     if proxy.isBuiltinByString(self.browseName()):
       self.__baseTypeEncoding__ = [self.browseName()]
       self.__encodable__ = True
-      log(self,  prefix + self.browseName() + "*")
-      log(self, "Encodable as: " + str(self.__baseTypeEncoding__))
-      log(self, "")
+      logger.debug( prefix + self.browseName() + "*")
+      logger.debug("Encodable as: " + str(self.__baseTypeEncoding__))
+      logger.debug("")
       return self.__baseTypeEncoding__
 
     if self.__xmlDefinition__ == None:
@@ -1505,7 +1507,7 @@ class opcua_node_dataType_t(opcua_node_t):
       for ref in self.getReferences():
         if "hassubtype" in ref.referenceType().browseName().lower() and ref.isForward() == False:
           if isinstance(ref.target(), opcua_node_dataType_t):
-            log(self,  prefix + "Attempting definition using supertype " + ref.target().browseName() + " for DataType " + " " + self.browseName())
+            logger.debug( prefix + "Attempting definition using supertype " + ref.target().browseName() + " for DataType " + " " + self.browseName())
             subenc = ref.target().buildEncoding(indent=indent+1)
             if not ref.target().isEncodable():
               self.__encodable__ = False
@@ -1513,15 +1515,15 @@ class opcua_node_dataType_t(opcua_node_t):
             else:
               self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [self.browseName(), subenc, 0]
       if len(self.__baseTypeEncoding__) == 0:
-        log(self, prefix + "No viable definition for " + self.browseName() + " " + str(self.id()) + " found.")
+        logger.debug(prefix + "No viable definition for " + self.browseName() + " " + str(self.id()) + " found.")
         self.__encodable__ = False
 
       if indent==0:
         if not self.__encodable__:
-          log(self, "Not encodable (partial): " + str(self.__baseTypeEncoding__))
+          logger.debug("Not encodable (partial): " + str(self.__baseTypeEncoding__))
         else:
-          log(self, "Encodable as: " + str(self.__baseTypeEncoding__))
-        log(self,  "")
+          logger.debug("Encodable as: " + str(self.__baseTypeEncoding__))
+        logger.debug( "")
 
       return self.__baseTypeEncoding__
 
@@ -1552,14 +1554,14 @@ class opcua_node_dataType_t(opcua_node_t):
             isSubType = False
           elif at == "ValueRank":
             hasValueRank = int(av)
-            log(self, "Arrays or matrices (ValueRank) are not supported for datatypes. This DT will become scalar.", LOG_LEVEL_WARN)
+            logger.warn("Arrays or matrices (ValueRank) are not supported for datatypes. This DT will become scalar.")
           else:
-            log(self, "Unknown Field Attribute " + str(at), LOG_LEVEL_WARN)
+            logger.warn("Unknown Field Attribute " + str(at))
         # This can either be an enumeration OR a structure, not both.
         # Figure out which of the dictionaries gets the newly read value pair
         if isEnum == isSubType:
           # This is an error
-          log(self, "DataType contains both enumeration and subtype (or neither)", LOG_LEVEL_WARN)
+          logger.warn("DataType contains both enumeration and subtype (or neither)")
           self.__encodable__ = False
           break
         elif isEnum:
@@ -1572,7 +1574,7 @@ class opcua_node_dataType_t(opcua_node_t):
           dtnode = self.getNamespace().getNodeByIDString(fdtype)
           if dtnode == None:
             # Node found in datatype element is invalid
-            log(self,  prefix + fname + " ?? " + av + " ??")
+            logger.debug( prefix + fname + " ?? " + av + " ??")
             self.__encodable__ = False
           else:
             # The node in the datatype element was found. we inherit its encoding,
@@ -1581,7 +1583,7 @@ class opcua_node_dataType_t(opcua_node_t):
             if hasValueRank < 0:
               hasValueRank = 0
             fdtype = str(dtnode.browseName()) + "+"*hasValueRank
-            log(self,  prefix + fname + " : " + fdtype + " -> " + str(dtnode.id()))
+            logger.debug( prefix + fname + " : " + fdtype + " -> " + str(dtnode.id()))
             subenc = dtnode.buildEncoding(indent=indent+1)
             self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + [[fname, subenc, hasValueRank]]
             if not dtnode.isEncodable():
@@ -1601,17 +1603,17 @@ class opcua_node_dataType_t(opcua_node_t):
       self.__baseTypeEncoding__ = self.__baseTypeEncoding__ + ['Int32']
       self.__definition__ = enumDict
       self.__isEnum__ = True
-      log(self,  prefix+"Int32* -> enumeration with dictionary " + str(enumDict) + " encodable " + str(self.__encodable__))
+      logger.debug( prefix+"Int32* -> enumeration with dictionary " + str(enumDict) + " encodable " + str(self.__encodable__))
       return self.__baseTypeEncoding__
 
     if indent==0:
       if not self.__encodable__:
-        log(self,  "Not encodable (partial): " + str(self.__baseTypeEncoding__))
+        logger.debug( "Not encodable (partial): " + str(self.__baseTypeEncoding__))
       else:
-        log(self,  "Encodable as: " + str(self.__baseTypeEncoding__))
+        logger.debug( "Encodable as: " + str(self.__baseTypeEncoding__))
         self.__isEnum__ = False
         self.__definition__ = typeDict
-      log(self,  "")
+      logger.debug( "")
     return self.__baseTypeEncoding__
 
   def parseXMLSubType(self, xmlelement):
@@ -1628,15 +1630,15 @@ class opcua_node_dataType_t(opcua_node_t):
           self.isAbstract(False)
         xmlelement.removeAttribute(at)
       else:
-        log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_WARN)
+        logger.warn("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
         if x.tagName == "Definition":
           self.__xmlDefinition__ = x
-          #log(self,  "Definition stored for future processing", LOG_LEVEL_DEBUG)
+          #logger.debug( "Definition stored for future processing")
         else:
-          log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_WARN)
+          logger.warn( "Unprocessable XML Element: " + x.tagName)
 
   def encodedTypeId(self):
     """ Returns a number of the builtin Type that should be used
@@ -1669,7 +1671,7 @@ class opcua_node_dataType_t(opcua_node_t):
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
-    
+
     # Detect if this is bootstrapping or if we are attempting to use userspace...
     if bootstrapping == False:
       typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
@@ -1684,20 +1686,20 @@ class opcua_node_dataType_t(opcua_node_t):
             myTypeRef = ref
             break
       if myTypeRef==None:
-        log(self, str(self) + " failed to locate a type definition, assuming BaseDataType.", LOG_LEVEL_WARN)
+        logger.warn(str(self) + " failed to locate a type definition, assuming BaseDataType.")
         code.append("       // No valid typeDefinition found; assuming BaseDataType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),")
       else:
         code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
         while myTypeRef in unPrintedReferences:
           unPrintedReferences.remove(myTypeRef)
-      
+
       if (self.isAbstract()):
         code.append("       true,")
       else:
         code.append("       false,")
       return code
-    
+
     if (self.isAbstract()):
       code.append(self.getCodePrintableID() + "->isAbstract = true;")
     else:
@@ -1725,16 +1727,16 @@ class opcua_node_view_t(opcua_node_t):
 
   def parseXMLSubtype(self, xmlelement):
     for (at, av) in xmlelement.attributes.items():
-      log(self, "Don't know how to process attribute " + at + " (" + av + ")", LOG_LEVEL_ERROR)
+      logger.error("Don't know how to process attribute " + at + " (" + av + ")")
 
     for x in xmlelement.childNodes:
       if x.nodeType == x.ELEMENT_NODE:
-        log(self,  "Unprocessable XML Element: " + x.tagName, LOG_LEVEL_INFO)
+        logger.info( "Unprocessable XML Element: " + x.tagName)
 
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
     code = []
     codegen = open62541_MacroHelper()
-    
+
     # Detect if this is bootstrapping or if we are attempting to use userspace...
     if bootstrapping == False:
       typeDefs = self.getNamespace().getSubTypesOf() # defaults to TypeDefinition
@@ -1749,18 +1751,18 @@ class opcua_node_view_t(opcua_node_t):
             myTypeRef = ref
             break
       if myTypeRef==None:
-        log(self, str(self) + " failed to locate a type definition, assuming BaseViewType.", LOG_LEVEL_WARN)
+        logger.warn(str(self) + " failed to locate a type definition, assuming BaseViewType.")
         code.append("       // No valid typeDefinition found; assuming BaseViewType")
         code.append("       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEViewTYPE),")
       else:
         code.append("       " + codegen.getCreateExpandedNodeIDMacro(myTypeRef.target()) + ",")
         while myTypeRef in unPrintedReferences:
           unPrintedReferences.remove(myTypeRef)
-          
+
       code.append("       // FIXME: Missing eventNotifier")
       code.append("       // FIXME: Missing containsNoLoops")
       return code
-    
+
     if self.containsNoLoops():
       code.append(self.getCodePrintableID() + "->containsNoLoops = true;")
     else: