All Downloads are FREE. Search and download functionalities are using the official Maven repository.

logging.WorkflowLogger.scala Maven / Gradle / Ivy

The newest version!
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//:
//:   Licensed under the Apache License, Version 2.0 (the "License");
//:   you may not use this file except in compliance with the License.
//:   You may obtain a copy of the License at
//:
//:       http://www.apache.org/licenses/LICENSE-2.0
//:
//:   Unless required by applicable law or agreed to in writing, software
//:   distributed under the License is distributed on an "AS IS" BASIS,
//:   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//:   See the License for the specific language governing permissions and
//:   limitations under the License.
//:
//: ----------------------------------------------------------------------------
package nelson
package logging

import journal.Logger
import scalaz.concurrent.Task
import scalaz._, Scalaz._
import scalaz.stream.{Process,Sink,sink}
import scalaz.stream.async.mutable.{Queue}
import java.nio.file.{Path,Files,StandardOpenOption}
import java.time.Instant


/*
 * The WorkflowLogger is a process that the logs workflow deployment progress
 * information to a namespaced file (based on deployment id). The main
 * purpose of this file is to provide the frontend with insight into
 * what is happening with this deployment, similar to what travis provides.
 */
class WorkflowLogger(queue: Queue[(ID, String)], base: Path) extends (LoggingOp ~> Task) {

  private val logger = Logger[this.type]

  import LoggingOp._
  def apply[A](op: LoggingOp[A]) =
    op match {
      case Debug(msg: String) =>
        Task.delay(logger.debug(msg))
      case Info(msg: String) =>
        Task.delay(logger.info(msg))
      case LogToFile(id, msg) =>
        log(id,msg)
    }

  def setup(): Task[Unit] =
    Task.delay {
      if (!exists(base)){
        logger.info(s"creating workflow log base directory at $base")
        Files.createDirectories(base)
        ()
      }
    }

  def log(id: ID, line: String): Task[Unit] =
    queue.enqueueOne((id, line))

  def process: Process[Task, Unit] =
    queue.dequeue to appendToFile

  def read(id: ID, offset: Int): Task[List[String]] = {
    for {
      file <- getPath(id)
      lines <- scalaz.stream.io.linesR(file.toFile.getAbsolutePath)
                 .drop(offset)
                 .runLog // yolo
                 .map(_.toList)
    } yield lines
  }

  private def appendToFile: Sink[Task,(ID,String)] =
    sink.lift { case (id, line) =>
      for {
        path <- getPath(id)
        _    <- createFile(path) >> append(path, line)
      } yield ()
    }

  private def append(path: Path, line: String): Task[Unit] =
    Task.delay {
      val withNewline = if (!line.endsWith("\n")) s"$line\n" else line
      val withTimestamp = s"$NOW: $withNewline"
      // This will open and close the file every time a line is added.
      // Ideally this would be a stream that we could write to and then
      // close when finished. This is to just get things going.
      Files.write(path, withTimestamp.getBytes(), StandardOpenOption.APPEND)
      ()
    }

  private def getPath(id: ID): Task[Path] =
    Task.delay(base.resolve(s"${id}.log"))

  private def createFile(path: Path): Task[Unit] =
    Task.delay {
      if (!exists(path))
        Files.createFile(path)
        ()
    }

  private def exists(path: Path): Boolean =
    Files.exists(path)

  private def NOW = Instant.now
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy