

.. _sphx_glr_auto_examples_unsorted_elog-slack.py:


=================
Slackbot for ELOG
=================




.. code-block:: python

    import os
    import re

    import pyinotify

    from pyslack import SlackClient    # pip install pyslack-real

    wm = pyinotify.WatchManager()
    mask = pyinotify.IN_CLOSE_WRITE

    URL = 'http://elog.km3net.de'
    # LOGBOOK_PATH = '/home/elog/elog'
    LOGBOOK_PATH = '/usr/local/elog/logbooks'
    BOTNAME = 'ELOG'
    DEFAULT_DESTINATION = '#elog'
    DESTINATIONS = {
        'Operations_IT': '#operations_it',
        'Operations_FR': '#operations_fr',
        #    'Qualification': '#elog',
        #    'DOM_Integration': '#elog',
        #    'DU_Integration': '#elog',
        #    'DAQ_Readout': '#elog',
        #    'Electronics': '#elog',
        #    'Analysis': '#elog',
        'Computing and Software': '#software',
    }

    slack = SlackClient("YOUR_SLACK_API_TOKEN_HERE")


    class ElogEntry(object):
        def __init__(self, logbook, msg_id=None):
            self.logbook = logbook
            self.id = msg_id
            self.header = {}
            self.content = ''

        @property
        def author(self):
            return self._lookup('Author')

        @property
        def type(self):
            return self._lookup('Type')

        @property
        def subject(self):
            return self._lookup('Subject')

        @property
        def url(self):
            escaped = re.sub(r"[\s_]+", '+', self.logbook)
            return URL + '/' + escaped + '/' + str(self.id)

        def _lookup(self, key):
            try:
                return self.header[key]
            except KeyError:
                return "Unknown"

        def __repr__(self):
            return ("ELOG entry from *{0.author}* in *{0.logbook}* (_{0.type}_):\n"
                    "*{0.subject}*\n{1}...\n<{0.url}>".format(
                        self, self.content[:150]))


    class ElogEntryBundle(object):
        def __init__(self, pathname):
            self.logbook = dirname(pathname)

            with open(pathname) as input_file:
                self.entries = self._parse_entries(input_file)

        @property
        def newest_entry(self):
            return self.entries[-1]

        def _parse_entries(self, input_file, msg_id=None):
            if msg_id is None:
                line = input_file.readline()
                if not line.startswith('$@MID@$:'):
                    raise ValueError("Not an ELOG-entry file!")
                msg_id = int(line.split(':')[1])

            entry = ElogEntry(self.logbook, msg_id)
            for line in input_file:
                if line.startswith(40 * '='):
                    break
                parameter, value = re.findall(r'([^:.]*): (.*)', line)[0]
                entry.header[parameter] = value
            for line in input_file:
                if line.startswith('$@MID@$:'):
                    msg_id = int(line.split(':')[1])
                    return [entry] + self._parse_entries(input_file, msg_id)
                else:
                    entry.content += line
            return [entry]


    class EventHandler(pyinotify.ProcessEvent):
        def my_init(self):
            self.logged_ids = []

        def process_IN_CLOSE_WRITE(self, event):
            if not self._is_valid_filetype(event.pathname):
                print("Not a valid filetype: {0}".format(event.pathname))
                return

            try:
                elog_bundle = ElogEntryBundle(event.pathname)
                elog_entry = elog_bundle.newest_entry
            except ValueError:
                print("Could not parse '{0}'. Ignoring...".format(event.pathname))
                return

            try:
                destination = DESTINATIONS[elog_entry.logbook]
            except KeyError:
                print("No destination for logbook '{0}'. Using only default..."
                      .format(elog_entry.logbook))
                destination = None
            finally:
                if elog_entry.id in self.logged_ids:
                    return    # For now skip, since it often duplicates!
                    pre = 'Updated '
                else:
                    pre = ''
                    self.logged_ids.append(elog_entry.id)
                message = pre + str(elog_entry)
                print(42 * "#")
                print("Filename: " + event.name)
                print("Elog Entry ID: " + str(elog_entry.id))
                print(42 * "-")
                print(message)
                print(42 * "/")
                if destination:
                    slack.chat_post_message(destination, message, username=BOTNAME)
                # else:
                slack.chat_post_message(
                    DEFAULT_DESTINATION, message, username=BOTNAME)

        def _is_valid_filetype(self, path):
            return path.endswith('.log')


    def dirname(filepath):
        return os.path.basename(os.path.dirname(filepath))


    handler = EventHandler()
    notifier = pyinotify.Notifier(wm, handler)
    wdd = wm.add_watch(LOGBOOK_PATH, mask, rec=True)

    notifier.loop()

**Total running time of the script:** ( 0 minutes  0.000 seconds)



.. only :: html

 .. container:: sphx-glr-footer


  .. container:: sphx-glr-download

     :download:`Download Python source code: elog-slack.py <elog-slack.py>`



  .. container:: sphx-glr-download

     :download:`Download Jupyter notebook: elog-slack.ipynb <elog-slack.ipynb>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.readthedocs.io>`_
