<commit_before>require "scrolls/parser"
require "scrolls/utils"

module Scrolls

  class TimeUnitError < RuntimeError; end

  module Log
    extend self

    extend Parser
    extend Utils

    LOG_LEVEL = (ENV['LOG_LEVEL'] || 3).to_i
    LOG_LEVEL_MAP = {
      "emergency" => 0,
      "alert"     => 1,
      "critical"  => 2,
      "error"     => 3,
      "warning"   => 4,
      "notice"    => 5,
      "info"      => 6,
      "debug"     => 7
    }

    def context
      Thread.current[:scrolls_context] ||= {}
    end

    def context=(h)
      Thread.current[:scrolls_context] = h
    end

    def global_context
      get_global_context
    end

    def global_context=(data)
      set_global_context(data)
    end

    def stream=(out=nil)
      @defined = out.nil? ? false : true

      @stream = sync_stream(out)
    end

    def stream
      @stream ||= sync_stream
    end

    def time_unit=(u)
      set_time_unit(u)
    end

    def time_unit
      @tunit ||= default_time_unit
    end

    def log(data, &blk)
      if gc = get_global_context
        ctx = gc.merge(context)
        logdata = ctx.merge(data)
      end

      unless blk
        write(logdata)
      else
        start = Time.now
        res = nil
        log(logdata.merge(:at => "start"))
        begin
          res = yield
        rescue StandardError, Timeout::Error => e
          log(
            :at           => "exception",
            :reraise      => true,
            :class        => e.class,
            :message      => e.message,
            :exception_id => e.object_id.abs,
            :elapsed      => calc_time(start, Time.now)
          )
          raise e
        end
        log(logdata.merge(:at => "finish", :elapsed => calc_time(start, Time.now)))
        res
      end
    end

    def log_exception(data, e)
      sync_stream(STDERR) unless @defined

      if gc = get_global_context
        logdata = gc.merge(data)
      end

      log(logdata.merge(
          :at => "exception",
          :class        => e.class,
          :message      => e.message,
          :exception_id => e.object_id.abs
      ))
      if e.backtrace
        bt = e.backtrace.reverse
        bt[0, bt.size-6].each do |line|
          log(logdata.merge(
              :at => "exception",
              :class => e.message,
              :exception_id => e.object_id.abs,
              :site => line.gsub(/[`'"]/, "")
          ))
        end
      end
    end

    def with_context(prefix)
      return unless block_given?
      old = context
      self.context = old.merge(prefix)
      yield if block_given?
      self.context = old
    end

    private

    def get_global_context
      default_global_context unless @global_context
      @global_context.value
    end

    def set_global_context(data=nil)
      default_global_context unless @global_context
      @global_context.update { |_| data }
    end

    def default_global_context
      @global_context = Atomic.new({})<commit_msg>Return the result of the block #20<commit_after>require "scrolls/parser"
require "scrolls/utils"

module Scrolls

  class TimeUnitError < RuntimeError; end

  module Log
    extend self

    extend Parser
    extend Utils

    LOG_LEVEL = (ENV['LOG_LEVEL'] || 3).to_i
    LOG_LEVEL_MAP = {
      "emergency" => 0,
      "alert"     => 1,
      "critical"  => 2,
      "error"     => 3,
      "warning"   => 4,
      "notice"    => 5,
      "info"      => 6,
      "debug"     => 7
    }

    def context
      Thread.current[:scrolls_context] ||= {}
    end

    def context=(h)
      Thread.current[:scrolls_context] = h
    end

    def global_context
      get_global_context
    end

    def global_context=(data)
      set_global_context(data)
    end

    def stream=(out=nil)
      @defined = out.nil? ? false : true

      @stream = sync_stream(out)
    end

    def stream
      @stream ||= sync_stream
    end

    def time_unit=(u)
      set_time_unit(u)
    end

    def time_unit
      @tunit ||= default_time_unit
    end

    def log(data, &blk)
      if gc = get_global_context
        ctx = gc.merge(context)
        logdata = ctx.merge(data)
      end

      unless blk
        write(logdata)
      else
        start = Time.now
        res = nil
        log(logdata.merge(:at => "start"))
        begin
          res = yield
        rescue StandardError, Timeout::Error => e
          log(
            :at           => "exception",
            :reraise      => true,
            :class        => e.class,
            :message      => e.message,
            :exception_id => e.object_id.abs,
            :elapsed      => calc_time(start, Time.now)
          )
          raise e
        end
        log(logdata.merge(:at => "finish", :elapsed => calc_time(start, Time.now)))
        res
      end
    end

    def log_exception(data, e)
      sync_stream(STDERR) unless @defined

      if gc = get_global_context
        logdata = gc.merge(data)
      end

      log(logdata.merge(
          :at => "exception",
          :class        => e.class,
          :message      => e.message,
          :exception_id => e.object_id.abs
      ))
      if e.backtrace
        bt = e.backtrace.reverse
        bt[0, bt.size-6].each do |line|
          log(logdata.merge(
              :at => "exception",
              :class => e.message,
              :exception_id => e.object_id.abs,
              :site => line.gsub(/[`'"]/, "")
          ))
        end
      end
    end

    def with_context(prefix)
      return unless block_given?
      old = context
      self.context = old.merge(prefix)
      res = yield if block_given?
      self.context = old
      res
    end

    private

    def get_global_context
      default_global_context unless @global_context
      @global_context.value
    end

    def set_global_context(data=nil)
      default_global_context unless @global_context
      @global_context.update { |_| data }
    end

    def default_global_context
      @global_context = Atomic.new({})
{'fraction_non_alphanumeric': 0.10620942234060263, 'fraction_numerical': 0.003995338771433328, 'mean_word_length': 1.6584070796460177, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1502851', 'n_tokens_mistral': 1928, 'n_tokens_neox': 1850, 'n_words': 421}