0

I'm developing an application where a lot of errors could occur. So I - and the administrators who shall use this application - have a lot of interest in logging all relevant information. But I'm struggling with ruby style guides. I love the rubocop defaults and normaly code fits in most cases. But with logging there have to be a lot more lines of code than in a normal application.

For Example see this construct

def do_something
  client.connect
  rescue FirstErrorType => e
    Logger.warn('Client') { "This is an error message for my Client: '#{e}'" }
    sleep 10
    retry
  rescue SecondErrorType => e
    Logger.warn('Client') {"This is an other error message for my Client: '#{e}'" }
    sleep 5
    retry
  rescue ThirdErrorType => e
    Logger.warn('Client') {"And even a third error message for my Client: '#{e}' "}
    sleep 30
    retry
  end
end

Is there a trick or a common pattern for logging sich errors in a style guide conform way? Or do I have to ignore style guide in this cases?

PascalTurbo
  • 2,189
  • 3
  • 24
  • 41
  • It's unclear for me what you asking. Can't get how a logger or error displaying relate to the ruby style guides. – Roman Kiselenko Aug 14 '16 at 08:48
  • For the above example you would get warnings, that the lines With "Logger" are too long and that the method "do_something" has to many lines of code. – PascalTurbo Aug 14 '16 at 08:50
  • Too many lines? So how many lines is normal? [80 char](https://github.com/bbatsov/rubocop/blob/master/config/default.yml#L547)? Do you know why? Why not split a _too long_ line into two separate line? What's the problem here? I never use `rubocop`, sorry, but it's stupid, I prefer to think about the code and logic, not about symbols and the string sizes. IMO – Roman Kiselenko Aug 14 '16 at 08:53

1 Answers1

0

There's a lot of repetition in here which is probably the cause of your problem. What you probably want to do is define a mapping table:

HANDLERS = {
  FirstErrorType => {
    level: :warn,
    scope: 'Client',
    message: "This is an error message for my Client",
    delay: 10
  },
  SecondErrorType => {
    level: :warn,
    scope: 'Client',
    message: "This is an other error message for my Client",
    delay: 5
  },
  ThirdErrorType => {
    level: :warn,
    scope: 'Client',
    message: "This is an other error message for my Client",
    delay: 30
  }
}

Then you can use this mapping table to recover from arbitrary errors where you code the actual mechanics behind this once and once only:

def do_something
  client.connect

rescue => e
  if (hander = HANDLERS[e.class])
    Logger.send(handler[:level], handler[:scope]) do
      '%s: %s' % [ handler[:message], e.to_s ]
    end

    sleep(handler[:delay])

    retry
  else
    raise e
  end
end

A more robust version of this would use metaprogramming in the style of the Rails rescue_from method where you have a small DSL to handle this sort of thing.

tadman
  • 208,517
  • 23
  • 234
  • 262