diff --git a/docs/source/specifications/metadata.org b/docs/source/specifications/metadata.org
index 139faf2def930e3b3c3c092c85e401c75d32f7ff..52d514a3465236a9079a8bba3ee721b013808a28 100644
--- a/docs/source/specifications/metadata.org
+++ b/docs/source/specifications/metadata.org
@@ -4,7 +4,7 @@ Draft for recommended metadata for images to provide a standard interface for al
 
 * Essential data
 - DimensionOrder: str
-  Order of dimensions (e.g., TCZYX for Channel, Time, Z,X,Y)
+  Order of dimensions (e.g., TCZYX for Time, Channel, Z, Y, X)
 - PixelSize: float
   Size of pixel, useful for segmentation.
 - Channels: List[str]
diff --git a/examples/tiler/pypipeline_unit_test_00_000001_Brightfield_003.tif b/examples/tiler/pypipeline_unit_test_00_000001_Brightfield_003.tif
index f813c15a9c8aef8a6e629ff17e460aef4acdb630..569f33a72ab18f65c79e28e38869a4f17cd30cca 100755
Binary files a/examples/tiler/pypipeline_unit_test_00_000001_Brightfield_003.tif and b/examples/tiler/pypipeline_unit_test_00_000001_Brightfield_003.tif differ
diff --git a/examples/tiler/pypipeline_unit_test_00_000001_Brightfield_003_square.tif b/examples/tiler/pypipeline_unit_test_00_000001_Brightfield_003_square.tif
new file mode 100755
index 0000000000000000000000000000000000000000..f813c15a9c8aef8a6e629ff17e460aef4acdb630
Binary files /dev/null and b/examples/tiler/pypipeline_unit_test_00_000001_Brightfield_003_square.tif differ
diff --git a/src/agora/abc.py b/src/agora/abc.py
index 6c1fd343e04bf42fb798642484b0b55c2de0a97a..c396b4b1503c7558dc51eaf9032b7cb14485bc38 100644
--- a/src/agora/abc.py
+++ b/src/agora/abc.py
@@ -10,6 +10,8 @@ from typing import Union
 from flatten_dict import flatten
 from yaml import dump, safe_load
 
+from agora.logging import timer
+
 atomic = t.Union[int, float, str, bool]
 
 
@@ -239,21 +241,12 @@ class StepABC(ProcessABC):
     def _run_tp(self):
         pass
 
-    def run_tp(self, tp: int, log: bool = True, **kwargs):
+    @timer
+    def run_tp(self, tp: int, **kwargs):
         """
         Time and log the timing of a step.
         """
-        if log:
-            t = perf_counter()
-            result = self._run_tp(tp, **kwargs)
-            self._log(
-                f"Timing:{self.__class__.__name__}:{perf_counter()-t}s",
-                "debug",
-            )
-        else:
-            result = self._run_tp(tp, **kwargs)
-
-        return result
+        return self._run_tp(tp, **kwargs)
 
     def run(self):
         # Replace run withn run_tp
diff --git a/src/agora/io/metadata.py b/src/agora/io/metadata.py
index 61caa3aa6c868f33a0f40ce220a02d3a3d028285..c058e9f430672a9fc4cb6a7e25d4e328368a2044 100644
--- a/src/agora/io/metadata.py
+++ b/src/agora/io/metadata.py
@@ -168,8 +168,9 @@ def get_meta_swainlab(parsed_metadata: dict):
 
 
 def get_meta_from_legacy(parsed_metadata: dict):
-    channels = parsed_metadata["channels/channel"]
-    return {"channels": channels}
+    result = parsed_metadata
+    result["channels"] = result["channels/channel"]
+    return result
 
 
 def parse_swainlab_metadata(filedir: t.Union[str, PosixPath]):
diff --git a/src/agora/io/signal.py b/src/agora/io/signal.py
index 1b174089ba5f176cdfb1a90be5fc7a16666ce243..0210ef3427552c8d7fa62a9f366976459d112e51 100644
--- a/src/agora/io/signal.py
+++ b/src/agora/io/signal.py
@@ -84,7 +84,7 @@ class Signal(BridgeH5):
         try:
             df.columns = (df.columns * self.tinterval // 60).astype(int)
         except Exception as e:
-            self._log(f"Unable to convert columns to minutes: {e}")
+            self._log(f"Unable to convert columns to minutes: {e}", "debug")
         return df
 
     @cached_property
diff --git a/src/agora/io/writer.py b/src/agora/io/writer.py
index bc8769a2ec44e5c3ff4bead42d0fdec53ea20ad1..264478482875c6992241ed9ad00613f0ef96fbf0 100644
--- a/src/agora/io/writer.py
+++ b/src/agora/io/writer.py
@@ -1,4 +1,3 @@
-import itertools
 import logging
 from collections.abc import Iterable
 from pathlib import Path
@@ -55,6 +54,11 @@ class DynamicWriter:
         if Path(file).exists():
             self.metadata = load_attributes(file)
 
+    def _log(self, message: str, level: str = "warn"):
+        # Log messages in the corresponding level
+        logger = logging.getLogger("aliby")
+        getattr(logger, level)(f"{self.__class__.__name__}: {message}")
+
     def _append(self, data, key, hgroup):
         """
         Append data to existing dataset in the h5 file otherwise create a new one.
@@ -170,7 +174,9 @@ class DynamicWriter:
                             self._append(value, key, hgroup)
                     except Exception as e:
                         print(key, value)
-                        raise (e)
+                        self._log(
+                            f"{key}:{value} could not be written: {e}", "error"
+                        )
             # write metadata
             for key, value in meta.items():
                 hgroup.attrs[key] = value
@@ -564,7 +570,7 @@ class Writer(BridgeH5):
                 dset[()] = df.index.get_level_values(level=name).tolist()
             # create dataset and write columns
             if (
-                df.columns.dtype == np.int
+                df.columns.dtype == int
                 or df.columns.dtype == np.dtype("uint")
                 or df.columns.name == "timepoint"
             ):
@@ -601,9 +607,7 @@ class Writer(BridgeH5):
                 )
                 # split indices in existing and additional
                 new = df.index.tolist()
-                if (
-                    df.index.nlevels == 1
-                ):
+                if df.index.nlevels == 1:
                     # cover cases with a single index
                     new = [(x,) for x in df.index.tolist()]
                 (
diff --git a/src/agora/logging.py b/src/agora/logging.py
new file mode 100644
index 0000000000000000000000000000000000000000..a004b0182363d495c32ffcb2edf9d51cd8875303
--- /dev/null
+++ b/src/agora/logging.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env jupyter
+"""
+Add general logging functions and decorators
+"""
+
+import logging
+from time import perf_counter
+
+
+def timer(func):
+    # Log duration of a function into aliby logfile
+    def wrap_func(*args, **kwargs):
+        t1 = perf_counter()
+        result = func(*args, **kwargs)
+        logging.getLogger("aliby").debug(
+            f"{func.__qualname__} took {(perf_counter()-t1):.4f}s"
+        )
+        return result
+
+    return wrap_func
diff --git a/src/aliby/pipeline.py b/src/aliby/pipeline.py
index 0062c61a75b96e2fe112f1cad2b637a842d19d49..f7f47cfb316bde17a6aad3a1abc6568f9397c294 100644
--- a/src/aliby/pipeline.py
+++ b/src/aliby/pipeline.py
@@ -475,7 +475,7 @@ class Pipeline(ProcessABC):
                                         step == "tiler"
                                         and i == min_process_from
                                     ):
-                                        print(
+                                        logging.getLogger("aliby").info(
                                             f"Found {steps['tiler'].n_traps} traps in {image.name}"
                                         )
                                     elif (
diff --git a/src/aliby/tile/tiler.py b/src/aliby/tile/tiler.py
index a3216e9eb7f0987238161a977249b4c74a1bb4dc..34aa89d1c2af76976f134a0fd38d58919cedc9bb 100644
--- a/src/aliby/tile/tiler.py
+++ b/src/aliby/tile/tiler.py
@@ -261,14 +261,13 @@ class Tiler(StepABC):
         """
         imgdmy_obj = ImageDummy(parameters)
         dummy_image = imgdmy_obj.get_data_lazy()
-        dummy_omero_metadata = (  # Default to "tczyx" if image.dimorder is None
-            {
-                f"size_{dim}": dim_size
-                for dim, dim_size in zip(
-                    imgdmy_obj.dimorder or "tczyx", dummy_image.shape
-                )
-            },
-        )
+        # Default to "tczyx" if image.dimorder is None
+        dummy_omero_metadata = {
+            f"size_{dim}": dim_size
+            for dim, dim_size in zip(
+                imgdmy_obj.dimorder or "tczyx", dummy_image.shape
+            )
+        }
         dummy_omero_metadata.update(
             {
                 "channels": [