]> git.donarmstrong.com Git - lilypond.git/commitdiff
Loglevels in our python scripts (lilypond-book, musicxml2ly, convert-ly)
authorReinhold Kainhofer <reinhold@kainhofer.com>
Sun, 7 Aug 2011 21:39:01 +0000 (23:39 +0200)
committerReinhold Kainhofer <reinhold@kainhofer.com>
Fri, 23 Sep 2011 14:08:18 +0000 (16:08 +0200)
Also use the env variables LILYPOND_BOOK_LOGLEVEL and LILYPOND_LOGLEVEL
in lilypond-book, unless overridden by cmd line options.

python/book_snippets.py
python/book_texinfo.py
python/lilylib.py
python/musicexp.py
python/musicxml.py
scripts/convert-ly.py
scripts/lilypond-book.py
scripts/musicxml2ly.py

index f128ac16fff8801f4c6f2774b37e160e543110d5..80584bdbca95762f30d4b8187633b25656245aa4 100644 (file)
@@ -15,6 +15,7 @@ import copy
 progress = ly.progress
 warning = ly.warning
 error = ly.error
+debug = ly.debug_output
 
 
 
@@ -717,8 +718,7 @@ printing diff against existing file." % filename)
     def filter_pipe (self, input, cmd):
         """Pass input through cmd, and return the result."""
 
-        if self.global_options.verbose:
-            progress (_ ("Running through filter `%s'\n") % cmd)
+        debug (_ ("Running through filter `%s'") % cmd, True)
 
         # TODO: Use Popen once we resolve the problem with msvcrt in Windows:
         (stdin, stdout, stderr) = os.popen3 (cmd)
@@ -744,8 +744,7 @@ printing diff against existing file." % filename)
             ly.stderr_write (stderr.read ())
             exit (status)
 
-        if self.global_options.verbose:
-            progress ('\n')
+        debug ('\n')
 
         return output
 
index 779cf566740aa8498d8d2f88a80b79747052c657..59a1d54e3cfbef0b03f1b8bbe011315907ebd950 100644 (file)
@@ -206,8 +206,7 @@ def get_texinfo_width_indent (source, global_options):
 
     # execute the command and pipe stdout to the parameter_string:
     cmd = 'LC_ALL=C %s -c -o %s %s' % (global_options.texinfo_program, outfile, tmpfile);
-    if (global_options.verbose):
-        progress ("Executing: %s\n" % cmd);
+    ly.debug_output ("Executing: %s\n" % cmd);
 
     proc = subprocess.Popen (cmd,
         universal_newlines=True, shell=True,
@@ -245,8 +244,7 @@ def get_texinfo_width_indent (source, global_options):
         exampleindent = "0.4\\in"
 
     retval = {LINE_WIDTH: textwidth, EXAMPLEINDENT: exampleindent}
-    if (global_options.verbose):
-        progress ("Auto-detected values are: %s\n" % retval);
+    ly.debug_output ("Auto-detected values are: %s\n" % retval);
     return retval;
 
 
index c83ac7dacb0ef09bf724a402638f9334b788ca92..e893aaa3a54482599374629d71ee514bd4eddfd5 100644 (file)
@@ -78,21 +78,70 @@ if at_re.match (program_version):
     else:
         program_version = "unknown"
 
+
+# Logging framework: We have the following output functions:
+#    error
+#    warning
+#    progress
+#    debug
+
+loglevels = {"NONE":0, "ERROR":1, "WARN":2, "BASIC":3, "PROGRESS":4, "INFO":5, "DEBUG":6}
+
+loglevel = loglevels["PROGRESS"]
+
+def set_loglevel (l):
+    global loglevel
+    newlevel = loglevels.get (l, -1)
+    if newlevel > 0:
+        debug_output (_ ("Setting loglevel to %s") % l)
+        loglevel = newlevel
+    else:
+        error (_ ("Unknown or invalid loglevel '%s'") % l)
+
+
+def handle_loglevel_option (option, opt_str, value, parser, *args):
+    if value:
+        set_loglevel (value);
+    elif args:
+        set_loglevel (args[0]);
+
+def is_loglevel (l):
+    global loglevel
+    return loglevel >= loglevels[l];
+
+def is_verbose ():
+    return is_loglevel ("DEBUG")
+
 def stderr_write (s):
     encoded_write (sys.stderr, s)
 
-def warning (s):
-    stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n')
+def print_logmessage (level, s, fullmessage = True):
+    if (is_loglevel (level)):
+        if fullmessage:
+            stderr_write (program_name + ": " + s + '\n')
+        else:
+            stderr_write (s)
 
 def error (s):
-    stderr_write (program_name + ": " + _ ("error: %s") % s + '\n')
+    print_logmessage ("ERROR", _ ("error: %s") % s);
+
+def warning (s):
+    print_logmessage ("WARN", _ ("warning: %s") % s);
+
+def basic_progress (s):
+    print_logmessage ("BASIC", s);
+
+def progress (s, fullmessage = False):
+    print_logmessage ("PROGRESS", s, fullmessage);
+
+def debug_output (s, fullmessage = False):
+    print_logmessage ("DEBUG", s, fullmessage);
 
-progress = stderr_write
 
 
 def require_python_version ():
     if sys.hexversion < 0x02040000:
-        stderr_write ("Python 2.4 or newer is required to run this program.\n\
+        error ("Python 2.4 or newer is required to run this program.\n\
 Please upgrade Python from http://python.org/download/, and if you use MacOS X,\n\
 please read 'Setup for MacOS X' in Application Usage.")
         os.system ("open http://python.org/download/")
index 68318678de073ea8ae5fec845dd6f8794793b94d..24174656273198be6d69abd7a7171fd1879d101b 100644 (file)
@@ -13,9 +13,6 @@ from rational import Rational
 previous_pitch = None
 relative_pitches = False
 
-def warning (str):
-    ly.stderr_write ((_ ("warning: %s") % str) + "\n")
-
 
 def escape_instrument_string (input_string):
     retstring = string.replace (input_string, "\"", "\\\"")
@@ -213,12 +210,12 @@ def pitch_generic (pitch, notenames, accidentals):
     # Handle remaining fraction to pitch.alteration (for microtones)
     if (halftones != pitch.alteration):
         if None in accidentals[1:3]:
-            warning (_ ("Language does not support microtones contained in the piece"))
+            ly.warning (_ ("Language does not support microtones contained in the piece"))
         else:
             try:
                 str += {-0.5: accidentals[1], 0.5: accidentals[2]}[pitch.alteration-halftones]
             except KeyError:
-                warning (_ ("Language does not support microtones contained in the piece"))
+                ly.warning (_ ("Language does not support microtones contained in the piece"))
     return str
 
 def pitch_general (pitch):
@@ -480,7 +477,7 @@ class TimeScaledMusic (MusicWrapper):
             func ("\\once \\override TupletBracket #'stencil = ##f")
             func.newline ()
         elif self.display_bracket == "curved":
-            warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
+            ly.warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
             func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
             func.newline ()
 
@@ -666,7 +663,7 @@ class RepeatedMusic:
             self.music = SequentialMusic ()
             self.music.elements = music
         else:
-            warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
+            ly.warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s") % \
                             {'music':music, 'repeat':self})
     def add_ending (self, music):
         self.endings.append (music)
@@ -675,7 +672,7 @@ class RepeatedMusic:
         if self.music:
             self.music.print_ly (printer)
         else:
-            warning (_ ("encountered repeat without body"))
+            ly.warning (_ ("encountered repeat without body"))
             printer.dump ('{}')
         if self.endings:
             printer.dump ('\\alternative {')
@@ -845,7 +842,7 @@ class ChordEvent (NestedMusic):
             # don't print newlines after the { and } braces
             self.grace_elements.print_ly (printer, False)
         elif self.grace_elements: # no self.elements!
-            warning (_ ("Grace note with no following music: %s") % self.grace_elements)
+            ly.warning (_ ("Grace note with no following music: %s") % self.grace_elements)
             if self.grace_type:
                 printer ('\\%s' % self.grace_type)
             else:
@@ -1007,7 +1004,7 @@ class OctaveShiftEvent (SpanEvent):
         try:
             value = {8: 1, 15: 2}[self.size]
         except KeyError:
-            warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
+            ly.warning (_ ("Invalid octave shift size found: %s. Using no shift.") % self.size)
             value = 0
         # negative values go up!
         value *= -1*self.span_type
@@ -1465,7 +1462,7 @@ class KeySignatureChange (Music):
         try:
             accidental = alter_dict[a[1]]
         except KeyError:
-            warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
+            ly.warning (_ ("Unable to convert alteration %s to a lilypond expression") % a[1])
             return ''
         if len (a) == 2:
             return "( %s . %s )" % (a[0], accidental)
index 7ba771fa8d6c77f72a27d1e47abd89ca91fcfa2c..278e108b1da4075b436ba8af7fe4ba0f7890f465 100644 (file)
@@ -9,9 +9,6 @@ import lilylib as ly
 
 _ = ly._
 
-def error (str):
-    ly.stderr_write ((_ ("error: %s") % str) + "\n")
-
 
 def escape_ly_output_string (input_string):
     return_string = input_string
@@ -76,23 +73,23 @@ class Xml_node:
         return ''.join ([c.get_text () for c in self._children])
 
     def message (self, msg):
-        ly.stderr_write (msg+'\n')
+        ly.warning (msg)
 
         p = self
         while p:
-            sys.stderr.write ('  In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
+            ly.progress ('  In: <%s %s>\n' % (p._name, ' '.join (['%s=%s' % item for item in p._attribute_dict.items ()])))
             p = p.get_parent ()
         
     def dump (self, indent = ''):
-        sys.stderr.write ('%s<%s%s>' % (indent, self._name, ''.join ([' %s=%s' % item for item in self._attribute_dict.items ()])))
+        ly.debug_output ('%s<%s%s>' % (indent, self._name, ''.join ([' %s=%s' % item for item in self._attribute_dict.items ()])))
         non_text_children = [c for c in self._children if not isinstance (c, Hash_text)]
         if non_text_children:
-            sys.stderr.write ('\n')
+            ly.debug_output ('\n')
         for c in self._children:
             c.dump (indent + "    ")
         if non_text_children:
-            sys.stderr.write (indent)
-        sys.stderr.write ('</%s>\n' % self._name)
+            ly.debug_output (indent)
+        ly.debug_output ('</%s>\n' % self._name)
 
         
     def get_typed_children (self, klass):
@@ -128,7 +125,7 @@ class Xml_node:
     def get_unique_typed_child (self, klass):
         cn = self.get_typed_children(klass)
         if len (cn) <> 1:
-            sys.stderr.write (self.__dict__ + '\n')
+            ly.error (self.__dict__)
             raise 'Child is not unique for', (klass, 'found', cn)
 
         return cn[0]
@@ -246,7 +243,7 @@ class Hash_comment (Music_xml_node):
     pass
 class Hash_text (Music_xml_node):
     def dump (self, indent = ''):
-        sys.stderr.write ('%s' % string.strip (self._data))
+        ly.debug_output ('%s' % string.strip (self._data))
 
 class Pitch (Music_xml_node):
     def get_step (self):
@@ -355,7 +352,7 @@ class Attributes (Measure_element):
 
             if mxl.get_maybe_exist_named_child ('senza-misura'):
                 # TODO: Handle pieces without a time signature!
-                error (_ ("Senza-misura time signatures are not yet supported!"))
+                ly.warning (_ ("Senza-misura time signatures are not yet supported!"))
                 return (4, 4)
             else:
                 signature = []
@@ -517,7 +514,7 @@ class Part_list (Music_xml_node):
         if instrument_name:
             return instrument_name
         else:
-            ly.stderr_write (_ ("Unable to find instrument for ID=%s\n") % id)
+            ly.warning (_ ("Unable to find instrument for ID=%s\n") % id)
             return "Grand Piano"
 
 class Part_group (Music_xml_node):
index 930c11da107db7bb24345a13216beaf6dc9c5fce..9f983540d6a2c4a1d3f7992d979bacd45dd36f68 100644 (file)
@@ -58,16 +58,8 @@ program_version = '@TOPLEVEL_VERSION@'
 authors = ('Jan Nieuwenhuizen <janneke@gnu.org>',
            'Han-Wen Nienhuys <hanwen@xs4all.nl>')
 
-error_file_write = ly.stderr_write
-
-def warning (s):
-    ly.stderr_write (program_name + ": " + _ ("warning: %s") % s + '\n')
-
-def error (s):
-    ly.stderr_write (program_name + ": " + _ ("error: %s") % s + '\n')
-
-def identify (port=sys.stderr):
-    ly.encoded_write (port, '%s (GNU LilyPond) %s\n' % (program_name, program_version))
+def identify ():
+    ly.progress ('%s (GNU LilyPond) %s\n' % (program_name, program_version))
 
 def warranty ():
     identify ()
@@ -107,6 +99,14 @@ def get_option_parser ():
     p.add_option ('-e', '--edit', help=_ ("edit in place"),
               action='store_true')
 
+    p.add_option ("-l", "--loglevel",
+                  help=_ ("Print log messages according to LOGLEVEL "
+                          "(NONE, ERROR, WARNING, PROGRESS (default), DEBUG)"),
+                  metavar=_ ("LOGLEVEL"),
+                  action='callback',
+                  callback=ly.handle_loglevel_option,
+                  type='string')
+
     p.add_option ('-n', '--no-version',
               help=_ ("do not add \\version command if missing"),
               action='store_true',
@@ -181,25 +181,23 @@ tuple (LAST,STR), with the last successful conversion and the resulting
 string."""
     conv_list = get_conversions (from_version, to_version)
 
-    error_file_write (_ ("Applying conversion: "))
+    ly.progress (_ ("Applying conversion: "))
 
     last_conversion = ()
     try:
         if not conv_list:
             last_conversion = to_version
         for x in conv_list:
-            error_file_write (tup_to_str (x[0]))
+            ly.progress (tup_to_str (x[0]))
             if x != conv_list[-1]:
-                error_file_write (', ')
+                ly.progress (', ')
             str = x[1] (str)
             last_conversion = x[0]
 
     except convertrules.FatalConversionError:
-        error_file_write ('\n'
-                          + _ ("Error while converting")
-                          + '\n'
-                          + _ ("Stopping at last successful rule")
-                          + '\n')
+        ly.error (_ ("Error while converting")
+                  + '\n'
+                  + _ ("Stopping at last successful rule"))
 
     return (last_conversion, str)
 
@@ -223,8 +221,7 @@ class InvalidVersion (Exception):
       self.version = version
 
 def do_one_file (infile_name):
-    ly.stderr_write (_ ("Processing `%s\'... ") % infile_name)
-    sys.stderr.write ('\n')
+    ly.progress (_ ("Processing `%s\'... ") % infile_name, True)
 
     if infile_name:
         infile = open (infile_name, 'r')
@@ -276,8 +273,8 @@ def do_one_file (infile_name):
                      '\\' + newversion, result)
         elif not global_options.skip_version_add:
             result = newversion + '\n' + result
-            
-        error_file_write ('\n')
+
+        ly.progress ('\n')
     
         if global_options.edit:
             try:
@@ -325,28 +322,28 @@ def main ():
         show_rules (sys.stdout, global_options.from_version, global_options.to_version)
         sys.exit (0)
 
-    identify (sys.stderr)
+    identify ()
 
     for f in files:
         if f == '-':
             f = ''
         elif not os.path.isfile (f):
-            error (_ ("%s: Unable to open file") % f)
+            ly.error (_ ("%s: Unable to open file") % f)
             if len (files) == 1:
                 sys.exit (1)
             continue
         try:
             do_one_file (f)
         except UnknownVersion:
-            error (_ ("%s: Unable to determine version.  Skipping") % f)
+            ly.error (_ ("%s: Unable to determine version.  Skipping") % f)
         except InvalidVersion:
             # Compat code for 2.x and 3.0 syntax ("except .. as v" doesn't 
             # work in python 2.4!):
             t, v, b = sys.exc_info ()
-            error (_ ("%s: Invalid version string `%s' \n"
-                      "Valid version strings consist of three numbers, "
-                      "separated by dots, e.g. `2.8.12'") % (f, v.version) )
+            ly.error (_ ("%s: Invalid version string `%s' \n"
+                         "Valid version strings consist of three numbers, "
+                         "separated by dots, e.g. `2.8.12'") % (f, v.version) )
 
-    sys.stderr.write ('\n')
+    ly.progress ('\n')
 
 main ()
index 0814739b47b890d3278ea66a5d8dc0442fd3fbe4..4d2b000fbd80252d9a3776244f6ad7a26aebdf5f 100644 (file)
@@ -91,7 +91,7 @@ authors = ('Jan Nieuwenhuizen <janneke@gnu.org>',
 
 ################################################################
 def exit (i):
-    if global_options.verbose:
+    if ly.is_verbose ():
         raise Exception (_ ('Exiting (%d)...') % i)
     else:
         sys.exit (i)
@@ -118,6 +118,7 @@ def warranty ():
         _ ("Distributed under terms of the GNU General Public License."),
         _ ("It comes with NO WARRANTY.")))
 
+
 def get_option_parser ():
     p = ly.get_option_parser (usage=_ ("%s [OPTION]... FILE") % 'lilypond-book',
                               description=help_summary,
@@ -158,6 +159,12 @@ def get_option_parser ():
                   type="float",
                   default=3.0)
 
+    p.add_option ('--lily-loglevel',
+                  help=_ ("Print lilypond log messages according to LOGLEVEL"),
+                  metavar=_ ("LOGLEVEL"),
+                  action='store', dest='lily_loglevel',
+                  default=os.environ.get ("LILYPOND_LOGLEVEL", None))
+
     p.add_option ('--lily-output-dir',
                   help=_ ("write lily-XXX files to DIR, link into --output dir"),
                   metavar=_ ("DIR"),
@@ -169,6 +176,14 @@ def get_option_parser ():
                   action='append', dest='custom_packages',
                   default=[])
 
+    p.add_option ("-l", "--loglevel",
+                  help=_ ("Print log messages according to LOGLEVEL "
+                          "(NONE, ERROR, WARNING, PROGRESS (default), DEBUG)"),
+                  metavar=_ ("LOGLEVEL"),
+                  action='callback',
+                  callback=ly.handle_loglevel_option,
+                  type='string')
+
     p.add_option ("-o", '--output', help=_ ("write output to DIR"),
                   metavar=_ ("DIR"),
                   action='store', dest='output_dir',
@@ -207,9 +222,9 @@ def get_option_parser ():
                   default=False)
 
     p.add_option ('-V', '--verbose', help=_ ("be verbose"),
-                  action="store_true",
-                  default=False,
-                  dest="verbose")
+                  action="callback",
+                  callback=ly.handle_loglevel_option,
+                  callback_args=("DEBUG",))
 
     p.version = "@TOPLEVEL_VERSION@"
     p.add_option("--version",
@@ -366,7 +381,7 @@ def system_in_directory (cmd, directory, logfile):
     current = os.getcwd()
     os.chdir (directory)
     ly.system(cmd,
-              be_verbose=global_options.verbose,
+              be_verbose=ly.is_verbose (),
               redirect_output=global_options.redirect_output,
               log_file=logfile,
               progress_p=1)
@@ -626,6 +641,8 @@ def do_options ():
 
 def main ():
     # FIXME: 85 lines of `main' macramee??
+    if (os.environ.has_key ("LILYPOND_BOOK_LOGLEVEL")):
+        ly.set_loglevel (os.environ["LILYPOND_BOOK_LOGLEVEL"])
     files = do_options ()
 
     basename = os.path.splitext (files[0])[0]
@@ -659,8 +676,16 @@ def main ():
 
     global_options.formatter.process_options (global_options)
 
-    if global_options.verbose:
-        global_options.process_cmd += " --verbose "
+    if global_options.lily_loglevel:
+        ly.debug_output (_ ("Setting LilyPond's loglevel to %s") % global_options.lily_loglevel, True)
+        global_options.process_cmd += " --loglevel=%s" % global_options.lily_loglevel
+    elif ly.is_verbose ():
+        if os.environ.get ("LILYPOND_LOGLEVEL", None):
+            ly.debug_output (_ ("Setting LilyPond's loglevel to %s (from environment variable LILYPOND_LOGLEVEL)") % os.environ.get ("LILYPOND_LOGLEVEL", None), True)
+            global_options.process_cmd += " --loglevel=%s" % os.environ.get ("LILYPOND_LOGLEVEL", None)
+        else:
+            ly.debug_output (_ ("Setting LilyPond's output to --verbose, implied by lilypond-book's setting"), True)
+            global_options.process_cmd += " --verbose"
 
     if global_options.padding_mm:
         global_options.process_cmd += " -deps-box-padding=%f " % global_options.padding_mm
index 2b630029b6223bbb061580201fa54f3874d66c31..322dfe91ae622bd5129dd299ed7e6c33ff251deb 100644 (file)
@@ -35,14 +35,6 @@ conversion_settings = Conversion_Settings ()
 # this layout and add the corresponding settings
 layout_information = musicexp.Layout ()
 
-def progress (str):
-    ly.stderr_write (str + '\n')
-    sys.stderr.flush ()
-
-def error_message (str):
-    ly.stderr_write (str + '\n')
-    sys.stderr.flush ()
-
 needed_additional_definitions = []
 additional_definitions = {
 
@@ -221,7 +213,10 @@ def extract_score_information (tree):
             app_description = ignore_beaming_software.get (s, False);
             if app_description:
                 conversion_settings.ignore_beaming = True
-                progress (_ ("Encountered file created by %s, containing wrong beaming information. All beaming information in the MusicXML file will be ignored") % app_description)
+                ly.warning (_ ("Encountered file created by %s, containing "
+                               "wrong beaming information. All beaming "
+                               "information in the MusicXML file will be "
+                               "ignored") % app_description)
 
     # TODO: Check for other unsupported features
     return header
@@ -237,9 +232,9 @@ class PartGroupInfo:
     def add_end (self, g):
         self.end[getattr (g, 'number', "1")] = g
     def print_ly (self, printer):
-        error_message (_ ("Unprocessed PartGroupInfo %s encountered") % self)
+        ly.warning (_ ("Unprocessed PartGroupInfo %s encountered") % self)
     def ly_expression (self):
-        error_message (_ ("Unprocessed PartGroupInfo %s encountered") % self)
+        ly.warning (_ ("Unprocessed PartGroupInfo %s encountered") % self)
         return ''
 
 def musicxml_step_to_lily (step):
@@ -512,9 +507,9 @@ def rational_to_lily_duration (rational_len):
         d.duration_log = d_log
         d.factor = Rational (rational_len.numerator ())
     else:
-        error_message (_ ("Encountered rational duration with denominator %s, "
+        ly.warning (_ ("Encountered rational duration with denominator %s, "
                        "unable to convert to lilypond duration") %
-                       rational_len.denominator ())
+                    rational_len.denominator ())
         # TODO: Test the above error message
         return None
 
@@ -759,7 +754,7 @@ def musicxml_time_to_lily (attributes):
 def musicxml_key_to_lily (attributes):
     key_sig = attributes.get_key_signature ()
     if not key_sig or not (isinstance (key_sig, list) or isinstance (key_sig, tuple)):
-        error_message (_ ("Unable to extract key signature!"))
+        ly.warning (_ ("Unable to extract key signature!"))
         return None
 
     change = musicexp.KeySignatureChange()
@@ -786,7 +781,7 @@ def musicxml_key_to_lily (attributes):
             start_pitch.step = n
             start_pitch.alteration = a
         except  KeyError:
-            error_message (_ ("unknown mode %s, expecting 'major' or 'minor' "
+            ly.warning (_ ("unknown mode %s, expecting 'major' or 'minor' "
                 "or a church mode!") % mode)
 
         fifth = musicexp.Pitch()
@@ -924,7 +919,7 @@ class Marker (musicexp.Music):
         self.direction = 0
         self.event = None
     def print_ly (self, printer):
-        ly.stderr_write (_ ("Encountered unprocessed marker %s\n") % self)
+        ly.warning (_ ("Encountered unprocessed marker %s\n") % self)
         pass
     def ly_expression (self):
         return ""
@@ -1018,7 +1013,7 @@ def musicxml_spanner_to_lily_event (mxl_event):
     if func:
         ev = func()
     else:
-        error_message (_ ('unknown span event %s') % mxl_event)
+        ly.warning (_ ('unknown span event %s') % mxl_event)
 
 
     type = mxl_event.get_type ()
@@ -1028,7 +1023,7 @@ def musicxml_spanner_to_lily_event (mxl_event):
     if span_direction != None:
         ev.span_direction = span_direction
     else:
-        error_message (_ ('unknown span type %s for %s') % (type, name))
+        ly.warning (_ ('unknown span type %s for %s') % (type, name))
 
     ev.set_span_type (type)
     ev.line_type = getattr (mxl_event, 'line-type', 'solid')
@@ -1448,12 +1443,12 @@ def musicxml_metronome_to_ly (mxl_event):
             except ValueError:
                 pass
         else:
-            error_message (_ ("Unknown metronome mark, ignoring"))
+            ly.warning (_ ("Unknown metronome mark, ignoring"))
             return
         return ev
     else:
         #TODO: Implement the other (more complex) way for tempo marks!
-        error_message (_ ("Metronome marks with complex relations (<metronome-note> in MusicXML) are not yet implemented."))
+        ly.warning (_ ("Metronome marks with complex relations (<metronome-note> in MusicXML) are not yet implemented."))
         return
 
 # translate directions into Events, possible values:
@@ -1655,7 +1650,7 @@ def musicxml_chordkind_to_lily (kind):
     res = chordkind_dict.get (kind, None)
     # Check for None, since a major chord is converted to ''
     if res == None:
-        error_message (_ ("Unable to convert chord type %s to lilypond.") % kind)
+        ly.warning (_ ("Unable to convert chord type %s to lilypond.") % kind)
     return res
 
 def musicxml_harmony_to_lily_chordname (n):
@@ -1956,8 +1951,8 @@ class LilyPondVoiceBuilder:
         diff = moment - current_end
 
         if diff < Rational (0):
-            error_message (_ ('Negative skip %s (from position %s to %s)') %
-                             (diff, current_end, moment))
+            ly.warning (_ ('Negative skip %s (from position %s to %s)') %
+                           (diff, current_end, moment))
             diff = Rational (0)
 
         if diff > Rational (0) and not (self.ignore_skips and moment == 0):
@@ -2433,7 +2428,7 @@ def musicxml_voice_to_lily_voice (voice):
 
 
     if len (modes_found) > 1:
-       error_message (_ ('cannot simultaneously have more than one mode: %s') % modes_found.keys ())
+       ly.warning (_ ('cannot simultaneously have more than one mode: %s') % modes_found.keys ())
 
     if options.relative:
         v = musicexp.RelativeMusic ()
@@ -2541,7 +2536,7 @@ def get_all_voices (parts):
 
         part_ly_voices = {}
         for n, v in name_voice.items ():
-            progress (_ ("Converting to LilyPond expressions..."))
+            ly.progress (_ ("Converting to LilyPond expressions..."), True)
             # musicxml_voice_to_lily_voice returns (lily_voice, {nr->lyrics, nr->lyrics})
             part_ly_voices[n] = musicxml_voice_to_lily_voice (v)
 
@@ -2581,8 +2576,9 @@ information.""") % 'lilypond')
                  help=_ ("show version number and exit"))
 
     p.add_option ('-v', '--verbose',
-                  action = "store_true",
-                  dest = 'verbose',
+                  action="callback",
+                  callback=ly.handle_loglevel_option,
+                  callback_args=("DEBUG",),
                   help = _ ("be verbose"))
 
     p.add_option ('', '--lxml',
@@ -2613,6 +2609,14 @@ information.""") % 'lilypond')
                   action = "store",
                   help = _ ("use LANG for pitch names, e.g. 'deutsch' for note names in German"))
 
+    p.add_option ("--loglevel",
+                  help=_ ("Print log messages according to LOGLEVEL "
+                          "(NONE, ERROR, WARNING, PROGRESS (default), DEBUG)"),
+                  metavar=_ ("LOGLEVEL"),
+                  action='callback',
+                  callback=ly.handle_loglevel_option,
+                  type='string')
+
     p.add_option ('--nd', '--no-articulation-directions',
                   action = "store_false",
                   default = True,
@@ -2726,7 +2730,7 @@ def update_score_setup (score_structure, part_list, voices):
         part_id = part_definition.id
         nv_dict = voices.get (part_id)
         if not nv_dict:
-            error_message (_ ('unknown part in part-list: %s') % part_id)
+            ly.warning (_ ('unknown part in part-list: %s') % part_id)
             continue
 
         staves = reduce (lambda x,y: x+ y,
@@ -2788,7 +2792,7 @@ def read_musicxml (filename, compressed, use_lxml):
     raw_string = None
     if compressed:
         if filename == "-":
-             progress (_ ("Input is compressed, extracting raw MusicXML data from stdin") )
+             ly.progress (_ ("Input is compressed, extracting raw MusicXML data from stdin"), True)
              # unfortunately, zipfile.ZipFile can't read directly from
              # stdin, so copy everything from stdin to a temp file and read
              # that. TemporaryFile() will remove the file when it is closed.
@@ -2801,7 +2805,7 @@ def read_musicxml (filename, compressed, use_lxml):
                  bytes_read = sys.stdin.read (8192)
              z = zipfile.ZipFile (tmp, "r")
         else:
-            progress (_ ("Input file %s is compressed, extracting raw MusicXML data") % filename)
+            ly.progress (_ ("Input file %s is compressed, extracting raw MusicXML data") % filename, True)
             z = zipfile.ZipFile (filename, "r")
         container_xml = z.read ("META-INF/container.xml")
         if not container_xml:
@@ -2831,9 +2835,9 @@ def read_musicxml (filename, compressed, use_lxml):
 
 def convert (filename, options):
     if filename == "-":
-        progress (_ ("Reading MusicXML from Standard input ...") )
+        ly.progress (_ ("Reading MusicXML from Standard input ..."), True)
     else:
-        progress (_ ("Reading MusicXML from %s ...") % filename)
+        ly.progress (_ ("Reading MusicXML from %s ...") % filename, True)
 
     tree = read_musicxml (filename, options.compressed, options.use_lxml)
     score_information = extract_score_information (tree)
@@ -2866,9 +2870,9 @@ def convert (filename, options):
     else:
       output_ly_name = options.output_name + '.ly'
 
-    progress (_ ("Output to `%s'") % output_ly_name)
+    ly.progress (_ ("Output to `%s'") % output_ly_name, True)
     printer = musicexp.Output_printer()
-    #progress (_ ("Output to `%s'") % defs_ly_name)
+    #ly.progress (_ ("Output to `%s'") % defs_ly_name, True)
     if (options.output_name == "-"):
       printer.set_file (codecs.getwriter ("utf-8")(sys.stdout))
     else:
@@ -2933,7 +2937,7 @@ def main ():
     if filename and (filename == "-" or os.path.exists (filename)):
         voices = convert (filename, options)
     else:
-        progress (_ ("Unable to find input file %s") % basefilename)
+        ly.error (_ ("Unable to find input file %s") % basefilename)
 
 if __name__ == '__main__':
     main()