prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  cfme.log only showing on first test in a run.
  cfme.log link only appears on the first test from a selection but shows all logs from all tests in that run. Expected to have a separate log link for each test specific to that test. See attached
  ![screenshot from 2018-08-14 15-50-11](https://user-images.githubusercontent.com/18352403/44099182-fca60de6-9fd9-11e8-8525-27ca6032229f.png)
  
  
  </issue>
  <code>
  [start of artifactor/plugins/logger.py]
  1 """ Logger plugin for Artifactor
  2 
  3 Add a stanza to the artifactor config like this,
  4 artifactor:
  5     log_dir: /home/username/outdir
  6     per_run: test #test, run, None
  7     overwrite: True
  8     plugins:
  9         logger:
  10             enabled: True
  11             plugin: logger
  12             level: DEBUG
  13 """
  14 import os
  15 from logging import makeLogRecord
  16 from artifactor import ArtifactorBasePlugin
  17 from cfme.utils.log import make_file_handler
  18 
  19 
  20 class Logger(ArtifactorBasePlugin):
  21 
  22     class Test(object):
  23         def __init__(self, ident):
  24             self.ident = ident
  25             self.in_progress = False
  26             self.handler = None
  27 
  28         def close(self):
  29             if self.handle is not None:
  30                 self.handler.close()
  31                 self.handler = None
  32 
  33     def plugin_initialize(self):
  34         self.register_plugin_hook('start_test', self.start_test)
  35         self.register_plugin_hook('finish_test', self.finish_test)
  36         self.register_plugin_hook('log_message', self.log_message)
  37 
  38     def configure(self):
  39         self.configured = True
  40         self.level = self.data.get('level', 'DEBUG')
  41 
  42     @ArtifactorBasePlugin.check_configured
  43     def start_test(self, artifact_path, test_name, test_location, slaveid):
  44         if not slaveid:
  45             slaveid = "Master"
  46         test_ident = "{}/{}".format(test_location, test_name)
  47         if slaveid in self.store:
  48             if self.store[slaveid].in_progress:
  49                 print("Test already running, can't start another, logger")
  50                 return None
  51             self.store[slaveid].close()
  52         self.store[slaveid] = self.Test(test_ident)
  53         self.store[slaveid].in_progress = True
  54         filename = "{ident}-cfme.log".format(ident=self.ident)
  55         self.store[slaveid].handler = make_file_handler(
  56             filename,
  57             root=artifact_path,
  58             # we overwrite
  59             mode='w',
  60             level=self.level)
  61 
  62         self.fire_hook('filedump', test_location=test_location, test_name=test_name,
  63             description="cfme.log", slaveid=slaveid, contents="", file_type="log",
  64             display_glyph="align-justify", dont_write=True,
  65             os_filename=os.path.join(artifact_path, filename),
  66             group_id="pytest-logfile")
  67 
  68     @ArtifactorBasePlugin.check_configured
  69     def finish_test(self, artifact_path, test_name, test_location, slaveid):
  70         if not slaveid:
  71             slaveid = "Master"
  72         self.store[slaveid].in_progress = False
  73         self.store[slaveid].close()
  74 
  75     @ArtifactorBasePlugin.check_configured
  76     def log_message(self, log_record, slaveid):
  77         # json transport fallout: args must be a dict or a tuple, json makes a tuple into a list
  78         args = log_record['args']
  79         log_record['args'] = tuple(args) if isinstance(args, list) else args
  80         record = makeLogRecord(log_record)
  81         if not slaveid:
  82             slaveid = "Master"
  83         if slaveid in self.store:
  84             handler = self.store[slaveid].handler
  85             if handler and record.levelno >= handler.level:
  86                 handler.handle(record)
  87
  [end of artifactor/plugins/logger.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/artifactor/plugins/logger.py b/artifactor/plugins/logger.py
  --- a/artifactor/plugins/logger.py
  +++ b/artifactor/plugins/logger.py
  @@ -26,7 +26,7 @@
               self.handler = None
   
           def close(self):
  -            if self.handle is not None:
  +            if self.handler is not None:
                   self.handler.close()
                   self.handler = None
  
verification_info: {"golden_diff": "diff --git a/artifactor/plugins/logger.py b/artifactor/plugins/logger.py\n--- a/artifactor/plugins/logger.py\n+++ b/artifactor/plugins/logger.py\n@@ -26,7 +26,7 @@\n             self.handler = None\n \n         def close(self):\n-            if self.handle is not None:\n+            if self.handler is not None:\n                 self.handler.close()\n                 self.handler = None\n", "issue": "cfme.log only showing on first test in a run.\ncfme.log link only appears on the first test from a selection but shows all logs from all tests in that run. Expected to have a separate log link for each test specific to that test. See attached\r\n![screenshot from 2018-08-14 15-50-11](https://user-images.githubusercontent.com/18352403/44099182-fca60de6-9fd9-11e8-8525-27ca6032229f.png)\r\n\n", "before_files": [{"content": "\"\"\" Logger plugin for Artifactor\n\nAdd a stanza to the artifactor config like this,\nartifactor:\n    log_dir: /home/username/outdir\n    per_run: test #test, run, None\n    overwrite: True\n    plugins:\n        logger:\n            enabled: True\n            plugin: logger\n            level: DEBUG\n\"\"\"\nimport os\nfrom logging import makeLogRecord\nfrom artifactor import ArtifactorBasePlugin\nfrom cfme.utils.log import make_file_handler\n\n\nclass Logger(ArtifactorBasePlugin):\n\n    class Test(object):\n        def __init__(self, ident):\n            self.ident = ident\n            self.in_progress = False\n            self.handler = None\n\n        def close(self):\n            if self.handle is not None:\n                self.handler.close()\n                self.handler = None\n\n    def plugin_initialize(self):\n        self.register_plugin_hook('start_test', self.start_test)\n        self.register_plugin_hook('finish_test', self.finish_test)\n        self.register_plugin_hook('log_message', self.log_message)\n\n    def configure(self):\n        self.configured = True\n        self.level = self.data.get('level', 'DEBUG')\n\n    @ArtifactorBasePlugin.check_configured\n    def start_test(self, artifact_path, test_name, test_location, slaveid):\n        if not slaveid:\n            slaveid = \"Master\"\n        test_ident = \"{}/{}\".format(test_location, test_name)\n        if slaveid in self.store:\n            if self.store[slaveid].in_progress:\n                print(\"Test already running, can't start another, logger\")\n                return None\n            self.store[slaveid].close()\n        self.store[slaveid] = self.Test(test_ident)\n        self.store[slaveid].in_progress = True\n        filename = \"{ident}-cfme.log\".format(ident=self.ident)\n        self.store[slaveid].handler = make_file_handler(\n            filename,\n            root=artifact_path,\n            # we overwrite\n            mode='w',\n            level=self.level)\n\n        self.fire_hook('filedump', test_location=test_location, test_name=test_name,\n            description=\"cfme.log\", slaveid=slaveid, contents=\"\", file_type=\"log\",\n            display_glyph=\"align-justify\", dont_write=True,\n            os_filename=os.path.join(artifact_path, filename),\n            group_id=\"pytest-logfile\")\n\n    @ArtifactorBasePlugin.check_configured\n    def finish_test(self, artifact_path, test_name, test_location, slaveid):\n        if not slaveid:\n            slaveid = \"Master\"\n        self.store[slaveid].in_progress = False\n        self.store[slaveid].close()\n\n    @ArtifactorBasePlugin.check_configured\n    def log_message(self, log_record, slaveid):\n        # json transport fallout: args must be a dict or a tuple, json makes a tuple into a list\n        args = log_record['args']\n        log_record['args'] = tuple(args) if isinstance(args, list) else args\n        record = makeLogRecord(log_record)\n        if not slaveid:\n            slaveid = \"Master\"\n        if slaveid in self.store:\n            handler = self.store[slaveid].handler\n            if handler and record.levelno >= handler.level:\n                handler.handle(record)\n", "path": "artifactor/plugins/logger.py"}]}