Skip to content

Commit 13666d6

Browse files
committed
Improved logging output with timestamps, level settings and more
This improves the logging output in several ways: * New logging functions log_debug/info/warn/error(). Almost all output now uses one of these functions. * Log messages start with timestamp. * Log messages of level warn/error are printed in red when logging to console. * New command line option: --log-level to set log level. Default is "info". The option -v, --verbose does the same as --log-level=debug. * New option --log-progress=true/false/auto. The default is `auto` which enables progress logging on the console and disables it when stderr has been redirected to a file. * Extra functions to log SQL commands/SQL COPY data. These can be activated by command line options --log-sql and --log-sql-data, respectively, instead of the compile time setting. Output is printed in blue when logging to console. Most log messages are in level "info" at the moment, so they are shown as before with the default settings. Many of these probably don't need to be shown in normal operation and can be downgraded to "debug". I'll leave this for a later commit. There are several places in the code where the output is updated on the screen while some longer process is running: * The code displaying regular updates of a counter in the expire code has been removed. Writing out the expire data doesn't take that long, so it isn't important to have this. Instead a log message is now generated. * The output of the objects being processed and the pending ways and relations output is now en/disabled by the `--log-progress` option. Otherwise it has not been touched. I'll leave cleaning that up for a later time. Some error reporting code has also been changed. Usually errors should be reported by throwing an exception that is then caught in the main() function and written out. The exception should contain the whole error message, sometimes additional logging lines are created before throwing the error. There is probably some more cleanup needed here. This introduces a new global object "the_logger". Otherwise we'd have to add the logger as parameter to a lot of functions! Fixes #202 Fixes #1246 Fixes #591
1 parent 70a9890 commit 13666d6

27 files changed

Lines changed: 434 additions & 218 deletions

docs/osm2pgsql.1

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ Add \f[B]\-v, \-\-verbose\f[] to display more verbose help.
5656
Print osm2pgsql version.
5757
.RS
5858
.RE
59+
.SH LOGGING OPTIONS
60+
.TP
61+
.B \-\-log\-level=LEVEL
62+
Set log level (`debug', `info' (default), `warn', or `error').
63+
.RS
64+
.RE
65+
.TP
66+
.B \-\-log\-sql
67+
Enable logging of SQL commands for debugging.
68+
.RS
69+
.RE
70+
.TP
71+
.B \-\-log\-sql\-data
72+
Enable logging of all data added to the database.
73+
This will write out a huge amount of data! For debugging.
74+
.RS
75+
.RE
5976
.SH DATABASE OPTIONS
6077
.TP
6178
.B \-d, \-\-database=NAME

docs/osm2pgsql.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ Mandatory arguments to long options are mandatory for short options too.
4747
-V, \--version
4848
: Print osm2pgsql version.
4949

50+
# LOGGING OPTIONS
51+
52+
\--log-level=LEVEL
53+
: Set log level ('debug', 'info' (default), 'warn', or 'error').
54+
55+
\--log-progress=VALUE
56+
: Enable (`true`) or disable (`false`) progress logging. The default is
57+
`auto` which will enable progress logging on the console and disable it
58+
if the output is redirected to a file.
59+
60+
\--log-sql
61+
: Enable logging of SQL commands for debugging.
62+
63+
\--log-sql-data
64+
: Enable logging of all data added to the database. This will write out
65+
a huge amount of data! For debugging.
66+
67+
-v, \--verbose
68+
: Same as `--log-level=debug`.
69+
5070
# DATABASE OPTIONS
5171

5272
-d, \--database=NAME

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(osm2pgsql_lib_SOURCES
99
geometry-processor.cpp
1010
id-tracker.cpp
1111
input-handler.cpp
12+
logging.cpp
1213
middle-pgsql.cpp
1314
middle-ram.cpp
1415
node-persistent-cache.cpp

src/db-check.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include "db-check.hpp"
2-
#include "format.hpp"
2+
#include "logging.hpp"
33
#include "pgsql.hpp"
44
#include "version.hpp"
55

@@ -28,7 +28,7 @@ void check_db(options_t const &options)
2828
auto const settings = get_postgresql_settings(db_connection);
2929

3030
try {
31-
fmt::print("Database version: {}\n", settings.at("server_version"));
31+
log_info("Database version: {}", settings.at("server_version"));
3232

3333
auto const version_str = settings.at("server_version_num");
3434
auto const version = std::strtoul(version_str.c_str(), nullptr, 10);

src/db-copy.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "db-copy.hpp"
44
#include "format.hpp"
5+
#include "logging.hpp"
56
#include "pgsql.hpp"
67

78
void db_deleter_by_id_t::delete_rows(std::string const &table,
@@ -151,7 +152,7 @@ void db_copy_thread_t::thread_t::operator()()
151152

152153
m_conn.reset();
153154
} catch (std::runtime_error const &e) {
154-
fmt::print(stderr, "DB copy thread failed: {}\n", e.what());
155+
log_error("DB copy thread failed: {}", e.what());
155156
exit(2);
156157
}
157158
}

src/expire-tiles.cpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "expire-tiles.hpp"
1818
#include "format.hpp"
19+
#include "logging.hpp"
1920
#include "options.hpp"
2021
#include "reprojection.hpp"
2122
#include "table.hpp"
@@ -31,10 +32,9 @@ tile_output_t::tile_output_t(char const *filename)
3132
: outfile(fopen(filename, "a"))
3233
{
3334
if (outfile == nullptr) {
34-
fmt::print(stderr,
35-
"Failed to open expired tiles file ({}). Tile expiry "
36-
"list will not be written!\n",
37-
std::strerror(errno));
35+
log_error("Failed to open expired tiles file ({}). Tile expiry "
36+
"list will not be written!",
37+
std::strerror(errno));
3838
}
3939
}
4040

@@ -52,10 +52,6 @@ void tile_output_t::output_dirty_tile(uint32_t x, uint32_t y, uint32_t zoom)
5252
}
5353

5454
fmt::print(outfile, "{}/{}/{}\n", zoom, x, y);
55-
++outcount;
56-
if (outcount % 1000 == 0) {
57-
fmt::print(stderr, "\rWriting dirty tile list ({}K)", outcount / 1000);
58-
}
5955
}
6056

6157
void expire_tiles::output_and_destroy(char const *filename, uint32_t minzoom)
@@ -297,8 +293,7 @@ void expire_tiles::from_wkb(char const *wkb, osmid_t osm_id)
297293
break;
298294
}
299295
default:
300-
fmt::print(stderr, "OSM id {}: Unknown geometry type, cannot expire.\n",
301-
osm_id);
296+
log_warn("OSM id {}: Unknown geometry type, cannot expire.", osm_id);
302297
}
303298
}
304299

@@ -359,10 +354,9 @@ void expire_tiles::from_wkb_polygon(ewkb::parser_t *wkb, osmid_t osm_id)
359354

360355
if (from_bbox(min.x, min.y, max.x, max.y)) {
361356
/* Bounding box too big - just expire tiles on the line */
362-
fmt::print(stderr,
363-
"\rLarge polygon ({:.0f} x {:.0f} metres, OSM ID {}"
364-
") - only expiring perimeter\n",
365-
max.x - min.x, max.y - min.y, osm_id);
357+
log_info("Large polygon ({:.0f} x {:.0f} metres, OSM ID {})"
358+
" - only expiring perimeter",
359+
max.x - min.x, max.y - min.y, osm_id);
366360
wkb->rewind(start);
367361
for (unsigned ring = 0; ring < num_rings; ++ring) {
368362
from_wkb_line(wkb);

src/expire-tiles.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <memory>
55
#include <unordered_set>
66

7+
#include "logging.hpp"
78
#include "osmtypes.hpp"
89
#include "pgsql.hpp"
910

@@ -30,7 +31,6 @@ struct xy_coord_t
3031
class tile_output_t
3132
{
3233
FILE *outfile;
33-
uint32_t outcount = 0;
3434

3535
public:
3636
tile_output_t(char const *filename);
@@ -93,6 +93,7 @@ struct expire_tiles
9393
* last_quadkey is initialized with a value which is not expected to exist
9494
* (larger than largest possible quadkey). */
9595
uint64_t last_quadkey = 1ULL << (2 * maxzoom);
96+
std::size_t count = 0;
9697
for (std::vector<uint64_t>::const_iterator it = tiles_maxzoom.cbegin();
9798
it != tiles_maxzoom.cend(); ++it) {
9899
for (uint32_t dz = 0; dz <= maxzoom - minzoom; ++dz) {
@@ -107,9 +108,11 @@ struct expire_tiles
107108
}
108109
xy_coord_t xy = quadkey_to_xy(qt_current, maxzoom - dz);
109110
output_writer.output_dirty_tile(xy.x, xy.y, maxzoom - dz);
111+
++count;
110112
}
111113
last_quadkey = *it;
112114
}
115+
log_info("Wrote {} entries to expired tiles list", count);
113116
}
114117

115118
/**

src/flex-table.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "flex-table.hpp"
22
#include "format.hpp"
3+
#include "logging.hpp"
34
#include "pgsql-helper.hpp"
45
#include "util.hpp"
56

@@ -174,8 +175,8 @@ void table_connection_t::start(bool append)
174175

175176
for (auto const &column : table()) {
176177
if (res.get_column_number(column.name()) < 0) {
177-
fmt::print(stderr, "Adding new column '{}' to '{}'\n",
178-
column.name(), table().name());
178+
log_info("Adding new column '{}' to '{}'", column.name(),
179+
table().name());
179180
m_db_connection->exec(
180181
"ALTER TABLE {} ADD COLUMN \"{}\" {}"_format(
181182
table().full_name(), column.name(),
@@ -204,8 +205,7 @@ void table_connection_t::stop(bool updateable, bool append)
204205
util::timer_t timer;
205206

206207
if (table().has_geom_column()) {
207-
fmt::print(stderr, "Clustering table '{}' by geometry...\n",
208-
table().name());
208+
log_info("Clustering table '{}' by geometry...", table().name());
209209

210210
// Notices about invalid geometries are expected and can be ignored
211211
// because they say nothing about the validity of the geometry in OSM.
@@ -229,7 +229,7 @@ void table_connection_t::stop(bool updateable, bool append)
229229

230230
sql += " ORDER BY ";
231231
if (postgis_version.major == 2 && postgis_version.minor < 4) {
232-
fmt::print(stderr, "Using GeoHash for clustering\n");
232+
log_info("Using GeoHash for clustering");
233233
if (table().geom_column().srid() == 4326) {
234234
sql += "ST_GeoHash({},10)"_format(table().geom_column().name());
235235
} else {
@@ -239,7 +239,7 @@ void table_connection_t::stop(bool updateable, bool append)
239239
}
240240
sql += " COLLATE \"C\"";
241241
} else {
242-
fmt::print(stderr, "Using native order for clustering\n");
242+
log_info("Using native order for clustering");
243243
// Since Postgis 2.4 the order function for geometries gives
244244
// useful results.
245245
sql += table().geom_column().name();
@@ -252,8 +252,7 @@ void table_connection_t::stop(bool updateable, bool append)
252252
table().full_tmp_name(), table().name()));
253253
m_id_index_created = false;
254254

255-
fmt::print(stderr, "Creating geometry index on table '{}'...\n",
256-
table().name());
255+
log_info("Creating geometry index on table '{}'...", table().name());
257256

258257
// Use fillfactor 100 for un-updateable imports
259258
m_db_connection->exec(
@@ -273,11 +272,11 @@ void table_connection_t::stop(bool updateable, bool append)
273272
}
274273
}
275274

276-
fmt::print(stderr, "Analyzing table '{}'...\n", table().name());
275+
log_info("Analyzing table '{}'...", table().name());
277276
m_db_connection->exec("ANALYZE " + table().full_name());
278277

279-
fmt::print(stderr, "All postprocessing on table '{}' done in {}.\n",
280-
table().name(), util::human_readable_duration(timer.stop()));
278+
log_info("All postprocessing on table '{}' done in {}.", table().name(),
279+
util::human_readable_duration(timer.stop()));
281280

282281
teardown();
283282
}
@@ -293,11 +292,9 @@ void table_connection_t::prepare()
293292
void table_connection_t::create_id_index()
294293
{
295294
if (m_id_index_created) {
296-
fmt::print(stderr, "Id index on table '{}' already created.\n",
297-
table().name());
295+
log_info("Id index on table '{}' already created.", table().name());
298296
} else {
299-
fmt::print(stderr, "Creating id index on table '{}'...\n",
300-
table().name());
297+
log_info("Creating id index on table '{}'...", table().name());
301298
m_db_connection->exec(table().build_sql_create_id_index());
302299
m_id_index_created = true;
303300
}

src/gazetteer-style.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "domain-matcher.hpp"
99
#include "format.hpp"
1010
#include "gazetteer-style.hpp"
11+
#include "logging.hpp"
1112
#include "pgsql.hpp"
1213
#include "wkb.hpp"
1314

@@ -81,7 +82,7 @@ std::string gazetteer_style_t::class_list() const
8182

8283
void gazetteer_style_t::load_style(std::string const &filename)
8384
{
84-
fmt::print(stderr, "Parsing gazetteer style file '{}'.\n", filename);
85+
log_info("Parsing gazetteer style file '{}'.", filename);
8586
pt::ptree root;
8687

8788
pt::read_json(filename, root);

src/geom-transform.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
#include "geom-transform.hpp"
3+
#include "logging.hpp"
34

45
#include <osmium/osm.hpp>
56

@@ -160,10 +161,9 @@ void init_geom_transform(geom_transform_t *transform, lua_State *lua_state)
160161

161162
if (std::strcmp(field, "create") != 0) {
162163
if (!transform->set_param(field, lua_state) && show_warning) {
163-
fmt::print(stderr,
164-
"\nWarning! Ignoring unknown field '{}' in geometry "
165-
"transformation description.\n",
166-
field);
164+
log_warn("Ignoring unknown field '{}' in geometry "
165+
"transformation description.",
166+
field);
167167
show_warning = false;
168168
}
169169
}

0 commit comments

Comments
 (0)