• Stars
    star
    128
  • Rank 272,403 (Top 6 %)
  • Language
    Clojure
  • License
    Other
  • Created over 4 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

In which we deal with exceptions the clojure way

ex

Exception handling library for clojure

Api docs

  • cljdoc badge ex

  • cljdoc badge ex-manifold

  • cljdoc badge ex-auspex (completable future)

  • cljdoc badge ex-http

Installation

Clojars Project

Clojars Project

Clojars Project

Clojars Project

Rationale

  • We want to be able to express/handle exceptions via ex-info in a more formalised way.

  • We want to be able to support java like exceptions hierarchies, without having to define/extend classes.

  • We want the shape of our custom ex-infos to be consistent.

  • We want to have a default/generic categorization of ex-infos

  • We don't want to differ from the original try/catch/finally semantics.

  • We want to have the same mechanism for manifold.deferred/catch, CompletableFuture, optional via separate deps.

  • We want to minimize any performance penalty it might have.

  • We don't want to emit catch Throwable, stay as close as possible to what the user would write by hand.

How

This is an exception library, drop in replacement for try/catch/finally, that adds support for ex-info/ex-data with a custom clojure hierarchy that allows to express exceptions relations. It also comes with manifold support.

So we have exoscale.ex/try+, which supports vanilla catch/finally clauses.

If you specify a catch clause with a keyword as first argument things get interesting. We assume you always put an :exoscale.ex/type or :type key in the ex-infos you generate, and will match its value to the value of the key in the catch clause.

The basics

Essentially catch takes this form:

(catch :something m
   ;; where m is a binding to the ex-data (you can destructure at that level as well)
   )

So you can do things like that.

(require '[exoscale.ex :as ex])

(ex/try+

  (throw (ex-info "Argh" {::ex/type ::bar :foo "a foo"}))

  (catch ::foo data
    (prn :got-ex-data data))

  (catch ::bar {:as data :keys [foo]}
    ;; in that case it would hit this one
    (prn :got-ex-data-again foo))

  (catch ExceptionInfo e
   ;; this would match an ex-info that didn't get a hit with catch-ex-info)

  (catch Exception e (prn :boring))

  (finally (prn :boring-too)))

Exception hierarchies

We leverage a clojure hierarchy so you can essentially create exceptions relations/extending without having to mess with Java classes directly.

;; so bar is a foo

(ex/derive ::bar ::foo)

(ex/try+
  (throw (ex-info "I am a bar" {::ex/type ::bar})
  (catch ::foo d
    (prn "got a foo with data" d)
    (prn "Original exception instance is " (-> d meta ::ex/exception))))

Manifold support

We have exoscale.ex.manifold/catch that matches the semantics of a catch block in try+ but with a more manifold like feel.

(require '[exoscale.ex.manifold :as mx])
(require '[manifold.deferred :as d])

(-> (d/error-deferred (ex-info "boom" {::ex/type :bar}))
    (mx/catch :bar (fn [data] (prn "ex-data is: " data)))
    (d/catch (fn [ex] "... regular manifold handling here")))

How to get to the original exception

You can also get the full exception instance via the metadata on the ex-data we extract, it's under the :exoscale.ex/exception key. If you are within a try+ block you can also access it directly via &ex

Our default internal error type table

We suggest you also either use one of these as ::ex/type or derive your own with these.

Within the namespace :exoscale.ex:

category retry fix
:unavailable yes make sure callee healthy
:interrupted yes stop interrupting
:incorrect no fix caller bug
:forbidden no fix caller creds
:unsupported no fix caller verb
:not-found no fix caller noun
:conflict no coordinate with callee
:fault no fix callee bug
:busy yes backoff and retry

This is very much inspired by cognitect-labs/anomalies.

We have simple wrappers to create ex-info based on this: ex/ex-unavailable, ex/ex-interrupted and so on. Their signature is identical to ex-info otherwise. An ex-http/response->ex-info utility function that maps HTTP status codes onto this taxonomy is available in the ex.http namespace.

How to generate/use good ex-infos

  • Specify a :exoscale.ex/type key always

  • The type key should either be one of our base type or a descendent. Descendents should be avoided when possible.

  • If it's a rethrow or comes from another exception pass the original exception as cause (3rd arg of ex-info)

  • Have logging in mind when you create them. It's easier to pull predefined set of values from ELK or aggregate than searching on a string message.

  • ex-infos should contain enough info but not too much (don't dump a system/env map on its ex-data).

  • Preferably select the data you want to show in your ex-data instead of removing what you want to hide. If for some reason secrets end up in the upstream data source at least there's is no risk of leaking them with the exception that way.

  • If you use more than once the same type you might want to spec it

  • Avoid returning raw values in error-deferreds, return properly formated ex-infos (d/error-deferred ::foo) vs (d/error-deferred (ex-info ".." {...}))

  • Do not leak data that is meant to emulate a usage context (cloudstack error codes, http status codes). That should be handled by a middleware at the edge.

Helpers

We have a few helpers

  • exoscale.ex/ex-info.

    ;; shortest, just a msg and {::ex/type ::incorrect}
    (ex/ex-info "Oh no" ::incorrect)
    
    ;; same with some ex-data
    (ex/ex-info "Oh no" ::incorrect {:foo :bar})
    
    ;; same with cause
    (ex/ex-info "Oh no" ::my-error {:foo :bar} cause)
    
    ;; including derivation
    (ex/ex-info "Oh no" [::foo [::incorrect ::sentry-loggable]])
    
    (ex/ex-info "Oh no" [::foo [::incorrect ::sentry-loggable]] {...})
  • ex/ex-unavailable,ex/ex-interrupted, etc

    They are just shortcuts to ex-info with preset :type matching our base type table and built in validation.

    (throw (ex/ex-unavailable "Cannot reach foo" {:because :this}))
  • for testing you can use in exoscale.ex.test thrown-ex-info-type? similar to thrown? in clojure.test.

    (is (thrown-ex-info-type? ::foo (throw (ex-info "boom" {:type ::foo})))) -> true

    It dispatches via try+/catch, so relations are supported.

  • we support turning these kind of ex-infos into data via clojure.core.protocols/datafy and back into exceptions via exoscale.ex/map->ex-info.

=> (clojure.core.protocols/datafy (ex/ex-incorrect "boom" {:a 1} (ex/ex-incorrect "the-cause")))
#:exoscale.ex{:type :exoscale.ex/incorrect
              :message "boom"
              :data {:a 1}
              :deriving #{:exoscale.ex/foo :exoscale.ex/bar}
              :cause #:exoscale.ex{:type :exoscale.ex/incorrect
                                   :message "the-cause"
                                   :data {...}
                                   :deriving #{:exoscale.ex/foo :exoscale.ex/bar}}

=> (type (ex/map->ex-info *1))
clojure.lang.ExceptionInfo

Usage examples

Some real life examples of usage for this:

  • Deny all display of user exceptions to the end-user by default via top level middleware and only let through the ones marked safe to show via a derived type.

  • Skip sentry logging for some kind of exceptions (or the inverse)

More Repositories

1

pithos

UNMAINTAINED - cassandra-backed object store. Retired backend for Exoscale's Simple Object Storage offering.
Clojure
282
star
2

coax

Clojure.spec coercion library for clj(s)
Clojure
116
star
3

riemann-grid

simple grid to view riemann states
CSS
111
star
4

seql

Simplfied EDN Query Language for SQL
Clojure
109
star
5

cs

A simple, yet powerful CloudStack API client for python and the command-line.
Python
85
star
6

cli

Command-line tool for everything at Exoscale: compute, storage, dns.
Go
82
star
7

interceptor

Small Interceptor lib for clojure
Clojure
81
star
8

multi-master-kubernetes

Multi-master Kubernetes cluster on Exoscale
Python
65
star
9

lingo

spec explain improved
Clojure
52
star
10

telex

simple jdk http wrappers
Clojure
43
star
11

exopaste

Clojure
38
star
12

openbsd-cloud-init

dependency-free initialization for OpenBSD cloud templates
Perl
34
star
13

egoscale

exoscale golang bindings
Go
29
star
14

deps-modules

Clojure
29
star
15

tools.project

Helpers to work with our tools.deps projects
Clojure
27
star
16

terraform-provider-exoscale

Terraform Exoscale provider
Go
25
star
17

collmann

riemann inside collectd
Clojure
24
star
18

python-riemann-wrapper

time and report exception in riemann for functions
Python
20
star
19

raven

clojure sentry library
Clojure
19
star
20

reporter

event, errors and metric reporting component
Clojure
18
star
21

ping-times

Toy single page application for blog post
Clojure
17
star
22

exoscale-circleci-nodejs

Deploying a NodeJS Application to Exoscale via CircleCI
JavaScript
16
star
23

cluster-api-provider-exoscale

Go
15
star
24

riemann-acknowledgement

helper streams for riemann to acknowledge alerts
Clojure
15
star
25

clojure-kubernetes-client

Clojure client for Kubernetes API
Clojure
14
star
26

liprug

operational status board
HTML
14
star
27

python-exoscale

Python bindings for the Exoscale APIs
Python
13
star
28

pullq

a variation on the idea of review-gator
Clojure
13
star
29

exoscale-cloud-controller-manager

Go
13
star
30

ansible-pgsql-demo

Deploying postgresql with high availability in seconds using Ansible on Exoscale
Makefile
13
star
31

yummy

YAML configuration for Clojure application
Clojure
12
star
32

collectd-puppet-reports

python collectd module to gather metrics from puppet reports
Python
11
star
33

automata

Moore-machine like finite state transducers
Clojure
11
star
34

packer-examples

How to build Exoscale templates with Packer and Qemu
Shell
9
star
35

vinyl

A Clojure facade for the FoundationDB record-layer
Clojure
9
star
36

clostack

clojure cloudstack client
Clojure
9
star
37

exoip

IP watchdog
Go
8
star
38

riemann-mysql

mysql replication health check for riemann
Go
8
star
39

collectd-cloudstack

collectd plugin for collecting usefull metrics from cloudstack API
Python
8
star
40

clojure-kubectl

Clojure wrapper for the Kubectl CLI
Clojure
7
star
41

vagrant-exoscale-boxes

Tooling to generate automatically vagrant dummy boxes for exoscale Open Cloud
Python
7
star
42

collectd-bird

Collectd plugin for BIRD routing daemon
Python
6
star
43

clj-yaml

YAML encoding and decoding for Clojure using SnakeYAML
HTML
5
star
44

cel-parser

Clojure CEL parser and interpreter
Clojure
5
star
45

rpp-c

rpp: riemann persistent ping
C
5
star
46

workshop-visibility

dotscale workshop on visibility
Puppet
4
star
47

examples

tutorials and other publicly available code by Exoscale
HTML
4
star
48

vault-plugin-secrets-exoscale

Exoscale Secrets Plugin for Vault
Go
3
star
49

automysqlbackup

automysqlbackup
Shell
3
star
50

pkg-i40e-dkms

Debian packaging for Intel i40e driver
3
star
51

collectd-smartmon

Collectd smartmon script
Shell
3
star
52

go-reporter

Logs, metrics and Sentry for Golang
Go
3
star
53

pkg-kernel-4.4

Debian packaging for Ubuntu kernel
C
2
star
54

collectd-quagga

Collectd plugin for Quagga routing daemon
Python
2
star
55

pkg-ixgbe-dkms

Debian packaging for ixgbe-dkms
2
star
56

packer-plugin-exoscale

Exoscale plugins for HashiCorp Packer
Go
2
star
57

sks-argocd

kubernetes manifests for deploying argocd on sks
HCL
2
star
58

cloak

Simple utility to prevent outputing secrets in unwanted places
Clojure
2
star
59

clojure-exoscale

A Clojure library for Exoscale resources
Clojure
2
star
60

packer-post-processor-exoscale-import

The Packer Exoscale Import post-processor plugin
Go
2
star
61

megaraid-collectd

collectd exec module to watch over megaraid status
Perl
2
star
62

angular-jobs

demo angularjs app
Clojure
2
star
63

collectd-cumulus

Collectd plugin for Cumulus switches (system)
Python
2
star
64

pkg-intel-microcode

Debian packaging for intel-microcode
2
star
65

go.mk

Base makefile for go projects
Makefile
2
star
66

runstatus-cli

Command-line client for Runstatus
Python
2
star
67

pallet-exoscale-demo

Demo infrastructure
CSS
2
star
68

quali

spec helper to (de-)qualify maps
Clojure
1
star
69

terms

Exoscale terms and conditions repository
1
star
70

zlocker

Zookeeper based isolated command execution
Go
1
star
71

pkg-puppetboard

Debian puppetboard packaging
1
star
72

quickstart-demos

Quickstart demos
HTML
1
star
73

pkg-frr

Debian packaging for frr
1
star
74

pkg-bird2

Debian packaging for bird2
1
star
75

pkg-puppetdb

Debian packaging for puppetdb
1
star
76

lein-replace

Transform your leiningen project with replace expressions
Clojure
1
star
77

pkg-zookeeper

Debian packaging for zookeeper
1
star
78

clobill

clojure hostbill client
Clojure
1
star
79

pkg-ipxe-qemu-256k-compat

Debian packaging for ipxe-qemu-256k-compat
1
star
80

vault-plugin-auth-exoscale

Vault "exoscale" Authentication Method
Go
1
star
81

pallet-exoscale

pallet provider for exoscale open cloud
Clojure
1
star
82

drawio-library

Official Exoscale Draw.io library for creating diagrams
1
star
83

cloudstack-restrictions

restriction manager for cloudstack
Java
1
star
84

docker-machine-driver-exo

Up to date docker-machine driver
Go
1
star
85

packer-builder-exoscale

Packer Builder plugin for Exoscale Compute instance templates
Go
1
star
86

homebrew-tap

Homebrew Formulae to Exoscale's cli binary
Ruby
1
star
87

cert-manager-webhook-exoscale

A cert-manager webhook for creating an ACME DNS01 solver webhook for Exoscale
Go
1
star
88

cumulus-cl-ports-puppet

Puppet module to manage switch port configuration on Cumulus Linux
Ruby
1
star
89

csv-to-riemann

Clojure app converting CSV files into Riemann events
Clojure
1
star
90

deps-version

Simple version management for tools.deps
Clojure
1
star
91

pkg-golang

Debian packaging for golang
1
star
92

clj-itsdangerous

clojure based partial implementation of pallets/itsdangerous
Clojure
1
star
93

data.xml

Functions to parse XML into lazy sequences and lazy trees and emit these as text
Clojure
1
star
94

ablauf

long-running workflow management
Clojure
1
star