def divert_to_file(self, req: "CamcopsRequest") -> None: """ Write an HL7 message to a file. For debugging. Args: req: a :class:`camcops_server.cc_modules.cc_request.CamcopsRequest` """ exported_task = self.exported_task recipient = exported_task.recipient filename = recipient.get_filename(req, exported_task.task, override_task_format="hl7") now_utc = get_now_utc_pendulum() log.info("Diverting HL7 message to file {!r}", filename) written = exported_task.export_file(filename=filename, text=str(self._hl7_msg)) if not written: return if recipient.hl7_debug_treat_diverted_as_sent: self.sent_at_utc = now_utc self.succeed(now_utc) else: self.abort("Exported to file as requested but not sent via HL7", diverted_not_sent=True)
def start(self, name: str, increment_count: bool = True) -> None: """ Start a named timer. Args: name: name of the timer increment_count: increment the start count for this timer """ if not self._timing: return now = get_now_utc_pendulum() # If we were already timing something else, pause that. if self._stack: last = self._stack[-1] self._totaldurations[last] += now - self._starttimes[last] # Start timing our new thing if name not in self._starttimes: self._totaldurations[name] = datetime.timedelta() self._count[name] = 0 self._starttimes[name] = now if increment_count: self._count[name] += 1 self._stack.append(name)
def stop(self, name: str) -> None: """ Stop a named timer. Args: name: timer to stop """ if not self._timing: return now = get_now_utc_pendulum() # Validity check if not self._stack: raise AssertionError("MultiTimer.stop() when nothing running") if self._stack[-1] != name: raise AssertionError(f"MultiTimer.stop({name!r}) when " f"{self._stack[-1]!r} is running") # Finish what we were asked to self._totaldurations[name] += now - self._starttimes[name] self._stack.pop() # Now, if we were timing something else before we started "name", # resume... if self._stack: last = self._stack[-1] self._starttimes[last] = now
def nlprp_datetime_now(as_local: bool = True) -> str: """ Returns the time now, as a string suitable for use with NLPRP. Args: as_local: use local timezone? (Otherwise, use UTC.) """ now = get_now_localtz_pendulum() if as_local else get_now_utc_pendulum() return pendulum_to_nlprp_datetime(now)
def reset(self) -> None: """ Reset the timers. """ self._overallstart = get_now_utc_pendulum() self._starttimes.clear() self._totaldurations.clear() self._count.clear() self._stack.clear()
def __init__(self, start: bool = True) -> None: """ Args: start: start the timer immediately? """ self._timing = start self._overallstart = get_now_utc_pendulum() self._starttimes = OrderedDict() # name: start time self._totaldurations = OrderedDict() # name: duration self._count = OrderedDict() # name: count self._stack = [] # list of names
def report(self) -> None: """ Finish and report to the log. """ while self._stack: self.stop(self._stack[-1]) now = get_now_utc_pendulum() grand_total = datetime.timedelta() overall_duration = now - self._overallstart for name, duration in self._totaldurations.items(): grand_total += duration log.info("Timing summary:") summaries = [] for name, duration in self._totaldurations.items(): n = self._count[name] total_sec = duration.total_seconds() mean = total_sec / n if n > 0 else None summaries.append({ 'total': total_sec, 'description': ( f"- {name}: {total_sec:.3f} s " f"({(100 * total_sec / grand_total.total_seconds()):.2f}%, " # noqa f"n={n}, mean={mean:.3f}s)"), }) summaries.sort(key=lambda x: x['total'], reverse=True) for s in summaries: # noinspection PyTypeChecker log.info(s["description"]) if not self._totaldurations: log.info("<no timings recorded>") unmetered = overall_duration - grand_total log.info( "Unmetered time: {:.3f} s ({:.2f}%)", unmetered.total_seconds(), 100 * unmetered.total_seconds() / overall_duration.total_seconds()) log.info("Total time: {:.3f} s", grand_total.total_seconds())
def send(self, host: str, username: str, password: str, port: int = None, use_tls: bool = True) -> bool: """ Sends message and returns success. """ if port is None: port = STANDARD_TLS_PORT if use_tls else STANDARD_SMTP_PORT msg = None msg_string = None if self.msg: msg = self.msg elif self.msg_string: msg_string = self.msg_string else: log.error("Can't send message; not present (not saved?)") return False if not password: log.error("Can't send message; password unknown") return False if self.sent: log.info("Resending message") self.host = host self.port = port self.username = username # don't save password self.use_tls = use_tls to_addrs = COMMASPACE.join(x for x in [self.to, self.cc, self.bcc] if x) header_components = filter( None, [ "To: {}".format(self.to) if self.to else "", "Cc: {}".format(self.cc) if self.cc else "", "Bcc: {}".format(self.bcc) if self.bcc else "", # noqa "Subject: {}".format(self.subject) if self.subject else "", ]) log.info("Sending email -- {}", " -- ".join(header_components)) try: send_msg( from_addr=self.from_addr, to_addrs=to_addrs, host=host, user=username, password=password, port=port, use_tls=use_tls, msg=msg, msg_string=msg_string, ) log.debug("... sent") self.sent = True self.sent_at_utc = get_now_utc_pendulum() self.sending_failure_reason = None except RuntimeError as e: log.error("Failed to send e-mail: {!s}", e) if not self.sent: self.sent = False self.sending_failure_reason = str(e)