Skip to content

Commit

Permalink
Merge PR #3016 by @GabrielXia - more metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
Cervator committed Jul 30, 2017
2 parents 7ccc454 + 30772b1 commit 3755293
Show file tree
Hide file tree
Showing 27 changed files with 890 additions and 52 deletions.
20 changes: 20 additions & 0 deletions engine/src/main/java/org/terasology/config/TelemetryConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public class TelemetryConfig {

private boolean launchPopupDisabled;

private String telemetryDestination;

private String errorReportingDestination;

public boolean isTelemetryEnabled() {
return telemetryEnabled;
}
Expand All @@ -50,6 +54,22 @@ public void setLaunchPopupDisabled(boolean launchPopupDisabled) {
this.launchPopupDisabled = launchPopupDisabled;
}

public String getTelemetryDestination() {
return telemetryDestination;
}

public void setTelemetryDestination(String telemetryDestination) {
this.telemetryDestination = telemetryDestination;
}

public String getErrorReportingDestination() {
return errorReportingDestination;
}

public void setErrorReportingDestination(String errorReportingDestination) {
this.errorReportingDestination = errorReportingDestination;
}

public void setTelemetryAndErrorReportingEnable(boolean enabled) {
telemetryEnabled = enabled;
errorReportingEnabled = enabled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.config.Config;
import org.terasology.config.TelemetryConfig;
import org.terasology.context.Context;
import org.terasology.engine.subsystem.EngineSubsystem;
import org.terasology.telemetry.Metrics;
import org.terasology.telemetry.TelemetryEmitter;
import org.terasology.telemetry.logstash.TelemetryLogstashAppender;

import java.net.MalformedURLException;
import java.net.URL;

/**
* This is a telemetry engine sub system.
* It will initialise all the telemetry stuff such as the {@link com.snowplowanalytics.snowplow.tracker.emitter.Emitter} and configure the {@link org.terasology.telemetry.logstash.TelemetryLogstashAppender}.
Expand All @@ -41,8 +43,6 @@ public class TelemetrySubSystem implements EngineSubsystem {

private Emitter emitter;

private Context context;

@Override
public String getName() {
return "Telemetry";
Expand All @@ -51,8 +51,6 @@ public String getName() {
@Override
public void preInitialise(Context rootContext) {

context = rootContext;

// Add metrics to context, this helps show metric values in ui
metrics = new Metrics();
rootContext.put(Metrics.class, metrics);
Expand All @@ -68,24 +66,40 @@ public void postInitialise(Context rootContext) {
metrics.initialise(rootContext);

addTelemetryLogstashAppender(rootContext);
setTelemetryDestinationIfEnable(rootContext);
}

private void addTelemetryLogstashAppender(Context rootContext) {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
TelemetryLogstashAppender telemetryLogstashAppender = new TelemetryLogstashAppender(rootContext);
lc.getLogger(Logger.ROOT_LOGGER_NAME).addAppender(telemetryLogstashAppender);
}

@Override
public void preShutdown() {

// TODO: REMOVE this when the telemetry is ready to users
Config config = context.get(Config.class);
TelemetryConfig telemetryConfig = config.getTelemetryConfig();
telemetryConfig.setTelemetryEnabled(false);
telemetryConfig.setErrorReportingEnabled(false);
Config config = rootContext.get(Config.class);
if (config.getTelemetryConfig().isErrorReportingEnabled()) {
String errorReportingDestination = config.getTelemetryConfig().getErrorReportingDestination();
if (errorReportingDestination != null) {
telemetryLogstashAppender.addDestination(errorReportingDestination);
telemetryLogstashAppender.start();
}
}
}

private void setTelemetryDestinationIfEnable(Context rootContext) {
Config config = rootContext.get(Config.class);
if (config.getTelemetryConfig().isTelemetryEnabled()) {
String telemetryDestination = config.getTelemetryConfig().getTelemetryDestination();
if (telemetryDestination != null) {
try {
URL url = new URL(telemetryDestination);
TelemetryEmitter telemetryEmitter = (TelemetryEmitter) emitter;
telemetryEmitter.changeUrl(url);
} catch (MalformedURLException e) {
logger.error("URL malformed", e);
}
}
}
}

@Override
public void shutdown() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,62 @@
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterMode;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.logic.characters.CharacterComponent;
import org.terasology.telemetry.GamePlayStatsComponent;
import org.terasology.world.block.BlockComponent;

import java.util.Map;

@RegisterSystem(RegisterMode.AUTHORITY)
public class EntityDestructionAuthoritySystem extends BaseComponentSystem {
@ReceiveEvent
public void onDestroy(DestroyEvent event, EntityRef entity) {
recordDestroyed(event,entity);
BeforeDestroyEvent destroyCheck = new BeforeDestroyEvent(event.getInstigator(), event.getDirectCause(), event.getDamageType());
entity.send(destroyCheck);
if (!destroyCheck.isConsumed()) {
entity.send(new DoDestroyEvent(event.getInstigator(), event.getDirectCause(), event.getDamageType()));
entity.destroy();
}
}

private void recordDestroyed(DestroyEvent event, EntityRef entityRef) {
EntityRef instigator = event.getInstigator();
if(entityRef.hasComponent(BlockComponent.class)) {
BlockComponent blockComponent = entityRef.getComponent(BlockComponent.class);
String blockName = blockComponent.getBlock().getDisplayName();
if (instigator.hasComponent(GamePlayStatsComponent.class)) {
GamePlayStatsComponent gamePlayStatsComponent = instigator.getComponent(GamePlayStatsComponent.class);
Map<String, Integer> blockDestroyedMap = gamePlayStatsComponent.blockDestroyedMap;
if (blockDestroyedMap.containsKey(blockName)) {
blockDestroyedMap.put(blockName, blockDestroyedMap.get(blockName) + 1);
} else {
blockDestroyedMap.put(blockName, 1);
}
instigator.saveComponent(gamePlayStatsComponent);
} else {
GamePlayStatsComponent gamePlayStatsComponent = new GamePlayStatsComponent();
Map<String, Integer> blockDestroyedMap = gamePlayStatsComponent.blockDestroyedMap;
blockDestroyedMap.put(blockName, 1);
instigator.addOrSaveComponent(gamePlayStatsComponent);
}
} else if (entityRef.hasComponent(CharacterComponent.class)) {
String monsterName = entityRef.getParentPrefab().getName();
if (instigator.hasComponent(GamePlayStatsComponent.class)) {
GamePlayStatsComponent gamePlayStatsComponent = instigator.getComponent(GamePlayStatsComponent.class);
Map<String, Integer> monsterKilled = gamePlayStatsComponent.monsterKilled;
if (monsterKilled.containsKey(monsterName)) {
monsterKilled.put(monsterName, monsterKilled.get(monsterName) + 1);
} else {
monsterKilled.put(monsterName, 1);
}
instigator.saveComponent(gamePlayStatsComponent);
} else {
GamePlayStatsComponent gamePlayStatsComponent = new GamePlayStatsComponent();
Map<String, Integer> monsterKilled = gamePlayStatsComponent.monsterKilled;
monsterKilled.put(monsterName, 1);
instigator.addOrSaveComponent(gamePlayStatsComponent);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.terasology.rendering.nui.databinding.ReadOnlyBinding;
import org.terasology.rendering.nui.widgets.ActivateEventListener;
import org.terasology.rendering.nui.widgets.UIButton;
import org.terasology.rendering.nui.widgets.UILabel;
import org.terasology.rendering.nui.widgets.UIText;

import java.util.function.Consumer;
Expand All @@ -40,6 +41,7 @@ public class AddServerPopup extends CoreScreenLayer {
private UIButton okButton;
private UIButton cancelButton;
private ServerInfo serverInfo;
private UILabel tip;

private Consumer<ServerInfo> successFunc;

Expand All @@ -51,6 +53,7 @@ public void initialise() {
portText = find("port", UIText.class);
okButton = find("ok", UIButton.class);
cancelButton = find("cancel", UIButton.class);
tip = find("tip", UILabel.class);

okButton.subscribe(button -> {

Expand Down Expand Up @@ -159,4 +162,8 @@ public void onSuccess(Consumer<ServerInfo> success) {
public void onCancel(ActivateEventListener listener) {
cancelButton.subscribe(listener);
}

public void removeTip() {
tip.setVisible(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2017 MovingBlocks
*
* 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.
*/
package org.terasology.telemetry;

import org.terasology.entitySystem.Component;
import org.terasology.network.Replicate;

import java.util.HashMap;
import java.util.Map;

/**
* A component stocks game play stats such as blocks destroyed, blocks placed, etc.
*/
public class GamePlayStatsComponent implements Component {

@Replicate
public Map<String, Integer> blockDestroyedMap = new HashMap<>();

@Replicate
public Map<String, Integer> blockPlacedMap = new HashMap<>();

@Replicate
public float distanceTraveled;

@Replicate
public float playTimeMinute;

@Replicate
public Map<String, Integer> monsterKilled = new HashMap<>();
}
55 changes: 54 additions & 1 deletion engine/src/main/java/org/terasology/telemetry/Metrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.context.Context;
import org.terasology.telemetry.metrics.BlockDestroyedMetric;
import org.terasology.telemetry.metrics.BlockPlacedMetric;
import org.terasology.telemetry.metrics.GameConfigurationMetric;
import org.terasology.telemetry.metrics.GamePlayMetric;
import org.terasology.telemetry.metrics.Metric;
import org.terasology.telemetry.metrics.ModulesMetric;
import org.terasology.telemetry.metrics.MonsterKilledMetric;
import org.terasology.telemetry.metrics.SystemContextMetric;

import java.lang.reflect.Field;
Expand All @@ -37,15 +42,43 @@ public class Metrics {

private ModulesMetric modulesMetric;

private GameConfigurationMetric gameConfigurationMetric;

private BlockDestroyedMetric blockDestroyedMetric;

private BlockPlacedMetric blockPlacedMetric;

private GamePlayMetric gamePlayMetric;

private MonsterKilledMetric monsterKilledMetric;

public Metrics() {

}

public void initialise(Context context) {

systemContextMetric = new SystemContextMetric();

modulesMetric = new ModulesMetric(context);
gameConfigurationMetric = new GameConfigurationMetric(context);
blockDestroyedMetric = new BlockDestroyedMetric();
blockPlacedMetric = new BlockPlacedMetric();
gamePlayMetric = new GamePlayMetric();
monsterKilledMetric = new MonsterKilledMetric();
}

public void refreshAllMetrics() {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getType().getSuperclass() == Metric.class) {
try {
Metric metric = (Metric) field.get(this);
metric.getFieldValueMap();
} catch (IllegalAccessException e) {
logger.error("The field is not inaccessible: ", e);
}
}
}
}

public SystemContextMetric getSystemContextMetric() {
Expand All @@ -56,6 +89,26 @@ public ModulesMetric getModulesMetric() {
return modulesMetric;
}

public GameConfigurationMetric getGameConfigurationMetric() {
return gameConfigurationMetric;
}

public BlockDestroyedMetric getBlockDestroyedMetric() {
return blockDestroyedMetric;
}

public BlockPlacedMetric getBlockPlacedMetric() {
return blockPlacedMetric;
}

public MonsterKilledMetric getMonsterKilledMetric() {
return monsterKilledMetric;
}

public GamePlayMetric getGamePlayMetric() {
return gamePlayMetric;
}

public Optional<Metric> getMetric(Class<?> cl) {
Optional<Metric> optional = Optional.ofNullable(null);
Field[] fields = this.getClass().getDeclaredFields();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ public class TelemetryEmitter extends BatchEmitter {

public static final String DEFAULT_COLLECTOR_HOST = "utility.terasology.org";

public static final int DEFAULT_COLLECTOR_PORT = 80;
public static final String DEFAULT_COLLECTOR_OWNER = "Terasology Community";

public static final int DEFAULT_COLLECTOR_PORT = 14654;

private static final Logger logger = LoggerFactory.getLogger(TelemetryEmitter.class);

Expand Down
28 changes: 28 additions & 0 deletions engine/src/main/java/org/terasology/telemetry/TelemetryParams.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
package org.terasology.telemetry;

import com.snowplowanalytics.snowplow.tracker.DevicePlatform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.security.MessageDigest;
import java.util.Base64;

/**
* Terasology desktop game parameters for telemetry. They are needed by snowplow stacks.
Expand All @@ -25,4 +32,25 @@ public class TelemetryParams {
public static final String APP_ID_TERASOLOGY = "terasology";

public static final DevicePlatform PLATFORM_DESKTOP = DevicePlatform.Desktop;

/**
* The user id is based on user's MAC address. Normally it differs from one to another.
* We hash the MAC address to protect personnel information.
*/
public static String userId;

private static final Logger logger = LoggerFactory.getLogger(TelemetryParams.class);

static {
try {
InetAddress address = InetAddress.getLocalHost();
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(address);
byte[] macAddress = networkInterface.getHardwareAddress();
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(macAddress);
userId = Base64.getEncoder().withoutPadding().encodeToString(hash);
} catch (Exception e) {
logger.error("Exception when getting MAC address", e);
}
}
}

0 comments on commit 3755293

Please sign in to comment.