ClickHouse / clickhouse-java

ClickHouse Java Clients & JDBC Driver
https://clickhouse.com
Apache License 2.0
1.44k stars 534 forks source link

Implement setClientInfo #691

Open piotrp opened 3 years ago

piotrp commented 3 years ago

Feature request: implement java.sql.Connection#setClientInfo (and ClickHouseDatabaseMetaData#getClientInfoProperties)

That would allow to pass some useful metadata to database, eg. frontend user that initiated current query, which would be then accessible in query_log. Or customized User-Agent from various parts of backend application without the need to create separate connection pools.

From a quick glance these properties would be useful:

zhicwu commented 3 years ago

Thanks @piotrp for the suggestion, let me see if I can put it into the next release.

Actually most of the properties are designed for clients using different protocols. This driver uses http protocol so the user agent header will only reflect on http_user_agent but not client_name, because the latter is reserved for native clients. On the other hand, log_comment is protocol irrelevant so it can be used on both sides.

I think we can start with below properties according to https://clickhouse.tech/docs/en/operations/system-tables/query_log/. Protocol Property Type Description
* log_comment String Log comment. It can be set to arbitrary string no longer than max_query_size. An empty string if it is not defined.
Native os_user? String Operating system username who runs clickhouse-client.
Native client_hostname String Hostname of the client machine where the clickhouse-client or another TCP client is run.
Native client_name String The clickhouse-client or another TCP client name.
Native client_revision UInt32 Revision of the clickhouse-client or another TCP client.
Native client_version_major UInt32 Major version of the clickhouse-client or another TCP client.
Native client_version_minor UInt32 Minor version of the clickhouse-client or another TCP client.
Native client_version_patch UInt32 Patch component of the clickhouse-client or another TCP client version.
HTTP http_user_agent String HTTP header UserAgent passed in the HTTP query.
HTTP http_referer String HTTP header Referer passed in the HTTP query (contains an absolute or partial address of the page making the query).
HTTP forwarded_for String HTTP header X-Forwarded-For passed in the HTTP query.

Note: property name in JDBC driver will be different as multiple protocols will be supported.

den-crane commented 3 years ago

BTW, "client_name (i.e. HTTP User Agent)" has been implemented -- setClientName


       ClickHouseProperties clickHouseProperties = new ClickHouseProperties(new Properties());
        clickHouseProperties.setUser("default");
        clickHouseProperties.setPassword("***");
        clickHouseProperties.setClientName("my_client_xxx");
        ClickHouseDataSource dataSource = new ClickHouseDataSource("jdbc:clickhouse://localhost:8123/default", clickHouseProperties);
        ClickHouseConnection connection = dataSource.getConnection();
        Statement stmt = connection.createStatement();
        ResultSet rs = stmt.executeQuery("select http_user_agent from system.processes");
        while (rs.next()) {
            System.out.println(rs.getString(1));
        }
        rs.close();
zhicwu commented 2 years ago

In the new JDBC driver, which currently only supports http and grpc two protocols:

piotrp commented 6 days ago

ApplicationName (ClickHouseConnection.PROP_APPLICATION_NAME) can't be changed on a connection when using JDBC driver 0.7.0. I noticed this after updating from 0.3.2-patch11 - driver always sends the original client_name that was present when connection was created.

When I have a Connection with client_name set to Abc and run the following code:

ds.connection.use { connection ->
    println("Original: " + connection.getClientInfo(ClickHouseConnection.PROP_APPLICATION_NAME))
    connection.setClientInfo(ClickHouseConnection.PROP_APPLICATION_NAME, "Custom")
    println("Customized: " + connection.getClientInfo(ClickHouseConnection.PROP_APPLICATION_NAME))

    connection.createStatement().use { stmt ->
        val ua =
            stmt.executeQuery("SELECT http_user_agent FROM system.processes WHERE query LIKE 'SELECT http_user_agent FROM system.processes%'")
                .use { rs ->
                    rs.next()
                    rs.getString(1)
                }
        println("Value sent do DB: $ua")
    }
}

I get the following output:

Original: Abc
Customized: Custom
Value sent do DB: Abc ClickHouse-JavaClient/0.7.0 (OpenJDK 64-Bit Server VM/Temurin-17.0.10+7; Apache-HttpClient/5.2.5)