Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v8.1.0 #58

Merged
merged 2 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).

### Unreleased

### [8.1.0] - 2025-02-03

- FEATURE: the index name can now be specified in the config
- style(es6): replace plugin with 'this'

### [8.0.4] - 2025-02-03

- dep(eslint): upgraded to v9
Expand Down Expand Up @@ -96,3 +101,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
[8.0.2]: https://github.com/haraka/haraka-plugin-elasticsearch/releases/tag/v8.0.2
[8.0.3]: https://github.com/haraka/haraka-plugin-elasticsearch/releases/tag/v8.0.3
[8.0.4]: https://github.com/haraka/haraka-plugin-elasticsearch/releases/tag/v8.0.4
[8.1.0]: https://github.com/haraka/haraka-plugin-elasticsearch/releases/tag/v8.1.0
2 changes: 1 addition & 1 deletion CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This handcrafted artisinal software is brought to you by:

| <img height="80" src="https://avatars.githubusercontent.com/u/261635?v=4"><br><a href="https://github.com/msimerson">msimerson</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=msimerson">75</a>) | <img height="80" src="https://avatars.githubusercontent.com/u/1674289?v=4"><br><a href="https://github.com/Dexus">Dexus</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=Dexus">2</a>) | <img height="80" src="https://avatars.githubusercontent.com/u/5239282?v=4"><br><a href="https://github.com/sriccio">sriccio</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=sriccio">2</a>) | <img height="80" src="https://avatars.githubusercontent.com/u/15035337?v=4"><br><a href="https://github.com/gtech99">gtech99</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=gtech99">1</a>) |
| <img height="80" src="https://avatars.githubusercontent.com/u/261635?v=4"><br><a href="https://github.com/msimerson">msimerson</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=msimerson">76</a>) | <img height="80" src="https://avatars.githubusercontent.com/u/1674289?v=4"><br><a href="https://github.com/Dexus">Dexus</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=Dexus">2</a>) | <img height="80" src="https://avatars.githubusercontent.com/u/5239282?v=4"><br><a href="https://github.com/sriccio">sriccio</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=sriccio">2</a>) | <img height="80" src="https://avatars.githubusercontent.com/u/15035337?v=4"><br><a href="https://github.com/gtech99">gtech99</a> (<a href="https://github.com/haraka/haraka-plugin-elasticsearch/commits?author=gtech99">1</a>) |
| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |

<sub>this file is generated by [.release](https://github.com/msimerson/.release).
Expand Down
6 changes: 6 additions & 0 deletions config/elasticsearch.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
;transaction=smtp-transaction
;connection=smtp-connection

; index interval. Example intervals (default: day):
; day : smtp-connection-2025-02-03
; month: smtp-connection-2025-02
; year : smtp-connection-2025
interval=day


; At the top level, each ES document has three categories: connection, message,
; and plugins. Those names can be customized here.
Expand Down
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default [
},

rules: {
'no-unused-vars': 0,
'no-unused-vars': 'warn',
},
},
]
135 changes: 66 additions & 69 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,69 +48,64 @@
}

exports.get_es_hosts = function () {
const plugin = this
plugin.cfg.es_hosts = [] // default: http://localhost:9200
this.cfg.es_hosts = [] // default: http://localhost:9200

if (!plugin.cfg.hosts) return // no [hosts] config
if (!this.cfg.hosts) return // no [hosts] config

for (const host in plugin.cfg.hosts) {
if (plugin.cfg.hosts[host]) {
plugin.cfg.es_hosts.push(plugin.cfg.hosts[host])
for (const host in this.cfg.hosts) {
if (this.cfg.hosts[host]) {
this.cfg.es_hosts.push(this.cfg.hosts[host])
} else {
plugin.cfg.es_hosts.push(`http://${host}:9200`)
this.cfg.es_hosts.push(`http://${host}:9200`)
}
}

plugin.clientArgs = { nodes: plugin.cfg.es_hosts }
if (plugin.cfg.auth) plugin.clientArgs.auth = plugin.cfg.auth
if (plugin.cfg.tls) plugin.clientArgs.tls = plugin.cfg.tls
this.clientArgs = { nodes: this.cfg.es_hosts }
if (this.cfg.auth) this.clientArgs.auth = this.cfg.auth
if (this.cfg.tls) this.clientArgs.tls = this.cfg.tls
}

exports.es_connect = function (done) {
const plugin = this
this.es = new Elasticsearch.Client(this.clientArgs)

plugin.es = new Elasticsearch.Client(plugin.clientArgs)

plugin.es
this.es
.ping()
.then(() => {
plugin.lognotice('connected')
this.lognotice('connected')
})
.catch((error) => {
plugin.logerror('cluster is down!')
plugin.logerror(util.inspect(error, { depth: null }))
this.logerror('cluster is down!')
this.logerror(util.inspect(error, { depth: null }))
})
.finally(() => {
if (done) done()
})
}

exports.log_transaction = function (next, connection) {
const plugin = this

if (plugin.cfg.ignore_hosts) {
if (plugin.cfg.ignore_hosts[connection.remote.host]) return next()
if (this.cfg.ignore_hosts) {
if (this.cfg.ignore_hosts[connection.remote.host]) return next()
}

const res = plugin.get_plugin_results(connection)
if (plugin.cfg.top_level_names && plugin.cfg.top_level_names.message) {
res[plugin.cfg.top_level_names.message] = res.message
const res = this.get_plugin_results(connection)
if (this.cfg.top_level_names && this.cfg.top_level_names.message) {
res[this.cfg.top_level_names.message] = res.message
delete res.message
}
res.timestamp = new Date().toISOString()

plugin.populate_conn_properties(connection, res)
plugin.es
this.populate_conn_properties(connection, res)
this.es
.create({
index: plugin.getIndexName('transaction'),
index: this.getIndexName('transaction'),
id: connection.transaction.uuid,
document: res,
})
.then((response) => {

Check warning on line 104 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

'response' is defined but never used

Check warning on line 104 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

'response' is defined but never used
// connection.loginfo(plugin, response);
// connection.loginfo(this, response);
})
.catch((error) => {
connection.logerror(plugin, error.message)
connection.logerror(this, error.message)
})

// hook reset_transaction doesn't seem to wait for next(). If I
Expand All @@ -122,38 +117,37 @@
}

exports.log_connection = function (next, connection) {
const plugin = this
if (!plugin.cfg.main.log_connections) return next()
if (!this.cfg.main.log_connections) return next()

if (plugin.cfg.ignore_hosts) {
if (plugin.cfg.ignore_hosts[connection.remote_host]) return next()
if (this.cfg.ignore_hosts) {
if (this.cfg.ignore_hosts[connection.remote_host]) return next()
}

if (
connection.notes.elasticsearch &&
connection.notes.elasticsearch === connection.tran_count
) {
connection.logdebug(plugin, 'skipping already logged txn')
connection.logdebug(this, 'skipping already logged txn')
return next()
}

const res = plugin.get_plugin_results(connection)
const res = this.get_plugin_results(connection)
res.timestamp = new Date().toISOString()

plugin.populate_conn_properties(connection, res)
this.populate_conn_properties(connection, res)

// connection.lognotice(plugin, JSON.stringify(res));
plugin.es
// connection.lognotice(this, JSON.stringify(res));
this.es
.create({
index: plugin.getIndexName('connection'),
index: this.getIndexName('connection'),
id: connection.uuid,
document: res,
})
.then((response) => {

Check warning on line 146 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

'response' is defined but never used

Check warning on line 146 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

'response' is defined but never used
// connection.loginfo(plugin, response);
// connection.loginfo(this, response);
})
.catch((error) => {
connection.logerror(plugin, error.message)
connection.logerror(this, error.message)
})

next()
Expand All @@ -169,35 +163,42 @@
}

exports.getIndexName = function (section) {
const plugin = this

// Elasticsearch indexes named like: smtp-connection-2017-05-05
// smtp-transaction-2017-05-05
// Elasticsearch indexes named like: smtp-connection-yyyy-mm-dd
// smtp-transaction-yyyy-mm-dd
let name = `smtp-${section}`
if (plugin.cfg.index && plugin.cfg.index[section]) {
name = plugin.cfg.index[section]
if (this.cfg.index && this.cfg.index[section]) {
name = this.cfg.index[section]
}
const date = new Date()

const d = date.getUTCDate().toString().padStart(2, '0')
const m = (date.getUTCMonth() + 1).toString().padStart(2, '0')
return `${name}-${date.getUTCFullYear()}-${m}-${d}`
const y = date.getUTCFullYear()

switch (this.cfg.index.interval) {
case 'year':
return `${name}-${y}`
case 'month':
return `${name}-${y}-${m}`
default:
return `${name}-${y}-${m}-${d}`
}
}

exports.populate_conn_properties = function (conn, res) {
const plugin = this
let conn_res = res

if (plugin.cfg.top_level_names && plugin.cfg.top_level_names.connection) {
if (!res[plugin.cfg.top_level_names.connection]) {
res[plugin.cfg.top_level_names.connection] = {}
if (this.cfg.top_level_names?.connection) {
if (!res[this.cfg.top_level_names.connection]) {
res[this.cfg.top_level_names.connection] = {}
}
conn_res = res[plugin.cfg.top_level_names.connection]
conn_res = res[this.cfg.top_level_names.connection]
}

conn_res.local = {
ip: conn.local.ip,
port: conn.local.port,
host: plugin.cfg.hostname || require('os').hostname(),
host: this.cfg.hostname || require('os').hostname(),
}
conn_res.remote = {
ip: conn.remote.ip,
Expand All @@ -214,8 +215,8 @@

if (!conn_res.auth) {
conn_res.auth = {}
if (plugin.cfg.top_level_names && plugin.cfg.top_level_names.plugin) {
const pia = plugin.cfg.top_level_names.plugin
if (this.cfg.top_level_names && this.cfg.top_level_names.plugin) {
const pia = this.cfg.top_level_names.plugin
if (res[pia] && res[pia].auth) {
conn_res.auth = res[pia].auth
delete res[pia].auth
Expand All @@ -235,12 +236,12 @@
trans: conn.tran_count,
}

for (const f in plugin.cfg.conn_props) {
for (const f in this.cfg.conn_props) {
if (conn[f] === undefined) return
if (conn[f] === 0) return
if (plugin.cfg.conn_props[f]) {
if (this.cfg.conn_props[f]) {
// alias specified
conn_res[plugin.cfg.conn_props[f]] = conn[f]
conn_res[this.cfg.conn_props[f]] = conn[f]
} else {
conn_res[f] = conn[f]
}
Expand Down Expand Up @@ -299,7 +300,6 @@
}

exports.populate_message = function (pir, connection) {
const plugin = this
pir.message = {
bytes: connection.transaction.data_bytes,
envelope: {
Expand Down Expand Up @@ -336,24 +336,23 @@
delete pir.queue
}

plugin.cfg.headers.forEach(function (h) {
for (const h of this.cfg.headers) {
const r = connection.transaction.header.get_decoded(h)
if (!r) return
pir.message.header[h] = r
})
}
}

exports.nest_plugin_results = function (res) {
const plugin = this
if (!plugin.cfg.top_level_names) return res
if (!plugin.cfg.top_level_names.plugin) return res
if (!this.cfg.top_level_names) return res
if (!this.cfg.top_level_names.plugin) return res

const new_res = {}
if (res.message) {
new_res.message = res.message
delete res.message
}
new_res[plugin.cfg.top_level_names.plugin] = res
new_res[this.cfg.top_level_names.plugin] = res
return new_res
}

Expand Down Expand Up @@ -401,8 +400,6 @@
}

exports.prune_noisy = function (res, pi) {
const plugin = this

if (res[pi].human) delete res[pi].human
if (res[pi].human_html) delete res[pi].human_html
if (res[pi]._watch_saw) delete res[pi]._watch_saw
Expand All @@ -424,7 +421,7 @@
delete res.dnsbl.pass
break
case 'fcrdns':
res.fcrdns.ptr_name_to_ip = plugin.objToArray(res.fcrdns.ptr_name_to_ip)
res.fcrdns.ptr_name_to_ip = this.objToArray(res.fcrdns.ptr_name_to_ip)
break
case 'geoip':
delete res.geoip.ll
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "haraka-plugin-elasticsearch",
"version": "8.0.4",
"version": "8.1.0",
"description": "Haraka plugin that saves logs to Elasticsearch",
"files": [
"CHANGELOG.md",
Expand Down Expand Up @@ -45,4 +45,4 @@
"singleQuote": true,
"semi": false
}
}
}