commit
68b0ee4e8d
|
@ -430,6 +430,10 @@ def run(hs):
|
||||||
stats["daily_active_rooms"] = yield hs.get_datastore().count_daily_active_rooms()
|
stats["daily_active_rooms"] = yield hs.get_datastore().count_daily_active_rooms()
|
||||||
stats["daily_messages"] = yield hs.get_datastore().count_daily_messages()
|
stats["daily_messages"] = yield hs.get_datastore().count_daily_messages()
|
||||||
|
|
||||||
|
r30_results = yield hs.get_datastore().count_r30_users()
|
||||||
|
for name, count in r30_results.iteritems():
|
||||||
|
stats["r30_users_" + name] = count
|
||||||
|
|
||||||
daily_sent_messages = yield hs.get_datastore().count_daily_sent_messages()
|
daily_sent_messages = yield hs.get_datastore().count_daily_sent_messages()
|
||||||
stats["daily_sent_messages"] = daily_sent_messages
|
stats["daily_sent_messages"] = daily_sent_messages
|
||||||
stats["cache_factor"] = CACHE_SIZE_FACTOR
|
stats["cache_factor"] = CACHE_SIZE_FACTOR
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from twisted.internet import defer
|
|
||||||
|
|
||||||
from synapse.storage.devices import DeviceStore
|
from synapse.storage.devices import DeviceStore
|
||||||
from .appservice import (
|
from .appservice import (
|
||||||
ApplicationServiceStore, ApplicationServiceTransactionStore
|
ApplicationServiceStore, ApplicationServiceTransactionStore
|
||||||
|
@ -244,13 +242,12 @@ class DataStore(RoomMemberStore, RoomStore,
|
||||||
|
|
||||||
return [UserPresenceState(**row) for row in rows]
|
return [UserPresenceState(**row) for row in rows]
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def count_daily_users(self):
|
def count_daily_users(self):
|
||||||
"""
|
"""
|
||||||
Counts the number of users who used this homeserver in the last 24 hours.
|
Counts the number of users who used this homeserver in the last 24 hours.
|
||||||
"""
|
"""
|
||||||
def _count_users(txn):
|
def _count_users(txn):
|
||||||
yesterday = int(self._clock.time_msec()) - (1000 * 60 * 60 * 24),
|
yesterday = int(self._clock.time_msec()) - (1000 * 60 * 60 * 24)
|
||||||
|
|
||||||
sql = """
|
sql = """
|
||||||
SELECT COALESCE(count(*), 0) FROM (
|
SELECT COALESCE(count(*), 0) FROM (
|
||||||
|
@ -264,8 +261,91 @@ class DataStore(RoomMemberStore, RoomStore,
|
||||||
count, = txn.fetchone()
|
count, = txn.fetchone()
|
||||||
return count
|
return count
|
||||||
|
|
||||||
ret = yield self.runInteraction("count_users", _count_users)
|
return self.runInteraction("count_users", _count_users)
|
||||||
defer.returnValue(ret)
|
|
||||||
|
def count_r30_users(self):
|
||||||
|
"""
|
||||||
|
Counts the number of 30 day retained users, defined as:-
|
||||||
|
* Users who have created their accounts more than 30 days
|
||||||
|
* Where last seen at most 30 days ago
|
||||||
|
* Where account creation and last_seen are > 30 days
|
||||||
|
|
||||||
|
Returns counts globaly for a given user as well as breaking
|
||||||
|
by platform
|
||||||
|
"""
|
||||||
|
def _count_r30_users(txn):
|
||||||
|
thirty_days_in_secs = 86400 * 30
|
||||||
|
now = int(self._clock.time_msec())
|
||||||
|
thirty_days_ago_in_secs = now - thirty_days_in_secs
|
||||||
|
|
||||||
|
sql = """
|
||||||
|
SELECT platform, COALESCE(count(*), 0) FROM (
|
||||||
|
SELECT
|
||||||
|
users.name, platform, users.creation_ts * 1000,
|
||||||
|
MAX(uip.last_seen)
|
||||||
|
FROM users
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT
|
||||||
|
user_id,
|
||||||
|
last_seen,
|
||||||
|
CASE
|
||||||
|
WHEN user_agent LIKE '%Android%' THEN 'android'
|
||||||
|
WHEN user_agent LIKE '%iOS%' THEN 'ios'
|
||||||
|
WHEN user_agent LIKE '%Electron%' THEN 'electron'
|
||||||
|
WHEN user_agent LIKE '%Mozilla%' THEN 'web'
|
||||||
|
WHEN user_agent LIKE '%Gecko%' THEN 'web'
|
||||||
|
ELSE 'unknown'
|
||||||
|
END
|
||||||
|
AS platform
|
||||||
|
FROM user_ips
|
||||||
|
) uip
|
||||||
|
ON users.name = uip.user_id
|
||||||
|
AND users.appservice_id is NULL
|
||||||
|
AND users.creation_ts < ?
|
||||||
|
AND uip.last_seen/1000 > ?
|
||||||
|
AND (uip.last_seen/1000) - users.creation_ts > 86400 * 30
|
||||||
|
GROUP BY users.name, platform, users.creation_ts
|
||||||
|
) u GROUP BY platform
|
||||||
|
"""
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
txn.execute(sql, (thirty_days_ago_in_secs,
|
||||||
|
thirty_days_ago_in_secs))
|
||||||
|
|
||||||
|
for row in txn:
|
||||||
|
if row[0] is 'unknown':
|
||||||
|
pass
|
||||||
|
results[row[0]] = row[1]
|
||||||
|
|
||||||
|
sql = """
|
||||||
|
SELECT COALESCE(count(*), 0) FROM (
|
||||||
|
SELECT users.name, users.creation_ts * 1000,
|
||||||
|
MAX(uip.last_seen)
|
||||||
|
FROM users
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT
|
||||||
|
user_id,
|
||||||
|
last_seen
|
||||||
|
FROM user_ips
|
||||||
|
) uip
|
||||||
|
ON users.name = uip.user_id
|
||||||
|
AND appservice_id is NULL
|
||||||
|
AND users.creation_ts < ?
|
||||||
|
AND uip.last_seen/1000 > ?
|
||||||
|
AND (uip.last_seen/1000) - users.creation_ts > 86400 * 30
|
||||||
|
GROUP BY users.name, users.creation_ts
|
||||||
|
) u
|
||||||
|
"""
|
||||||
|
|
||||||
|
txn.execute(sql, (thirty_days_ago_in_secs,
|
||||||
|
thirty_days_ago_in_secs))
|
||||||
|
|
||||||
|
count, = txn.fetchone()
|
||||||
|
results['all'] = count
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
return self.runInteraction("count_r30_users", _count_r30_users)
|
||||||
|
|
||||||
def get_users(self):
|
def get_users(self):
|
||||||
"""Function to reterive a list of users in users table.
|
"""Function to reterive a list of users in users table.
|
||||||
|
|
|
@ -48,6 +48,13 @@ class ClientIpStore(background_updates.BackgroundUpdateStore):
|
||||||
columns=["user_id", "device_id", "last_seen"],
|
columns=["user_id", "device_id", "last_seen"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.register_background_index_update(
|
||||||
|
"user_ips_last_seen_index",
|
||||||
|
index_name="user_ips_last_seen",
|
||||||
|
table="user_ips",
|
||||||
|
columns=["user_id", "last_seen"],
|
||||||
|
)
|
||||||
|
|
||||||
# (user_id, access_token, ip) -> (user_agent, device_id, last_seen)
|
# (user_id, access_token, ip) -> (user_agent, device_id, last_seen)
|
||||||
self._batch_row_update = {}
|
self._batch_row_update = {}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Remember to update this number every time a change is made to database
|
# Remember to update this number every time a change is made to database
|
||||||
# schema files, so the users will be informed on server restarts.
|
# schema files, so the users will be informed on server restarts.
|
||||||
SCHEMA_VERSION = 47
|
SCHEMA_VERSION = 48
|
||||||
|
|
||||||
dir_path = os.path.abspath(os.path.dirname(__file__))
|
dir_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* Copyright 2018 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
INSERT into background_updates (update_name, progress_json)
|
||||||
|
VALUES ('user_ips_last_seen_index', '{}');
|
Loading…
Reference in New Issue