Python using lxml to write an xml file with system performance data
<p>I am using the python modules <code>lxml</code> and <code>psutil</code> to record some system metrics to be placed in an XML file and copied to a remote server for parsing by php and displayed to a user. </p>

<p>However, lxml is giving me some trouble on pushing some variables, objects and such to the various parts of my XML.</p>

<p>For example:</p>

<pre><code>import psutil, os, time, sys, platform
from lxml import etree

# This creates &lt;metrics&gt;
root = etree.Element('metrics')

# and &lt;basic&gt;, to display basic information about the server
child1 = etree.SubElement(root, 'basic')

# First system/hostname, so we know what machine this is
etree.SubElement(child1, "name").text = socket.gethostname()

# Then boot time, to get the time the system was booted.
etree.SubElement(child1, "boottime").text = psutil.boot_time()

# and process count, see how many processes are running.
etree.SubElement(child1, "proccount").text = len(psutil.pids()) 
</code></pre>

<p>The line to get the system hostname works.</p>

<p>However the next two lines to get boot time and process count error out, with:</p>

<pre><code>&gt;&gt;&gt; etree.SubElement(child1, "boottime").text = psutil.boot_time()
Traceback (most recent call last):
 File "&lt;stdin&gt;", line 1, in &lt;module&gt;
 File "lxml.etree.pyx", line 921, in lxml.etree._Element.text.__set__ (src/lxml/lxml.etree.c:41344)
 File "apihelpers.pxi", line 660, in lxml.etree._setNodeText (src/lxml/lxml.etree.c:18894)
 File "apihelpers.pxi", line 1333, in lxml.etree._utf8 (src/lxml/lxml.etree.c:24601)
 TypeError: Argument must be bytes or unicode, got 'float'
&gt;&gt;&gt; etree.SubElement(child1, "proccount").text = len(psutil.pids())
Traceback (most recent call last):
 File "&lt;stdin&gt;", line 1, in &lt;module&gt;
 File "lxml.etree.pyx", line 921, in lxml.etree._Element.text.__set__ (src/lxml/lxml.etree.c:41344)
 File "apihelpers.pxi", line 660, in lxml.etree._setNodeText (src/lxml/lxml.etree.c:18894)
 File "apihelpers.pxi", line 1333, in lxml.etree._utf8 (src/lxml/lxml.etree.c:24601)
 TypeError: Argument must be bytes or unicode, got 'int'
</code></pre>

<p>So, here's what my XML looks like as printed:</p>

<pre><code>&gt;&gt;&gt; print(etree.tostring(root, pretty_print=True))
&lt;metrics&gt;
  &lt;basic&gt;
    &lt;name&gt;mercury&lt;/name&gt;
    &lt;boottime/&gt;
    &lt;proccount/&gt;
  &lt;/basic&gt;
&lt;/metrics&gt;
</code></pre>

<p>So, is there anyway to push floats and ints to xml text like I need? Or am I doing this completely wrong?</p>

<p>Thanks for any help you can provide.</p>

<p>The <code>text</code> field is expected to be unicode or str, not any other type (<code>boot_time</code> is <code>float</code>, and <code>len()</code> is int).
So just convert to string the non-string compliant elements:</p>

<pre><code># First system/hostname, so we know what machine this is
etree.SubElement(child1, "name").text = socket.gethostname() # nothing to do

# Then boot time, to get the time the system was booted.
etree.SubElement(child1, "boottime").text = str(psutil.boot_time())

# and process count, see how many processes are running.
etree.SubElement(child1, "proccount").text = str(len(psutil.pids()))
</code></pre>

<p>result:</p>

<pre><code>b'&lt;metrics&gt;\n  &lt;basic&gt;\n    &lt;name&gt;JOTD64&lt;/name&gt;\n    &lt;boottime&gt;1473903558.0&lt;/boottime&gt;\n    &lt;proccount&gt;121&lt;/proccount&gt;\n  &lt;/basic&gt;\n&lt;/metrics&gt;\n'
</code></pre>

<p>I suppose the library could do the <code>isinstance(str,x)</code> test or <code>str</code> conversion, but it was not designed that way (what if you want to display your floats with leading zeroes, truncated decimals...).
It operates faster if the lib assumes that everything is <code>str</code>, which it is most of the time.</p>

python lxml psutil